Merge "STL added IntOffset <-> Int to SpaceVectorConverter" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index a299408..8a69e86 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -23,7 +23,6 @@
         "aconfig_mediacodec_flags_java_lib",
         "aconfig_settingslib_flags_java_lib",
         "aconfig_trade_in_mode_flags_java_lib",
-        "android-sdk-flags-java",
         "android.adaptiveauth.flags-aconfig-java",
         "android.app.appfunctions.flags-aconfig-java",
         "android.app.assist.flags-aconfig-java",
@@ -63,6 +62,7 @@
         "android.os.vibrator.flags-aconfig-java",
         "android.permission.flags-aconfig-java",
         "android.provider.flags-aconfig-java",
+        "android.sdk.flags-aconfig-java",
         "android.security.flags-aconfig-java",
         "android.server.app.flags-aconfig-java",
         "android.service.autofill.flags-aconfig-java",
@@ -100,7 +100,7 @@
         "com.android.media.flags.performance-aconfig-java",
         "com.android.media.flags.projection-aconfig-java",
         "com.android.net.thread.platform.flags-aconfig-java",
-        "com.android.ranging.flags.ranging-aconfig-java",
+        "com.android.ranging.flags.ranging-aconfig-java-export",
         "com.android.server.contextualsearch.flags-java",
         "com.android.server.flags.services-aconfig-java",
         "com.android.text.flags-aconfig-java",
@@ -373,6 +373,11 @@
     name: "android.security.flags-aconfig-java-export",
     aconfig_declarations: "android.security.flags-aconfig",
     mode: "exported",
+    min_sdk_version: "30",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.wifi",
+    ],
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
@@ -647,6 +652,8 @@
     min_sdk_version: "30",
     apex_available: [
         "//apex_available:platform",
+        "com.android.art",
+        "com.android.art.debug",
         "com.android.permission",
     ],
 }
@@ -961,6 +968,13 @@
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
+java_aconfig_library {
+    name: "android.app.flags-aconfig-java-host",
+    aconfig_declarations: "android.app.flags-aconfig",
+    host_supported: true,
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
 // Broadcast Radio
 aconfig_declarations {
     name: "android.hardware.radio.flags-aconfig",
@@ -1193,6 +1207,7 @@
     name: "device_policy_aconfig_flags",
     package: "android.app.admin.flags",
     container: "system",
+    exportable: true,
     srcs: [
         "core/java/android/app/admin/flags/flags.aconfig",
     ],
@@ -1205,6 +1220,18 @@
 }
 
 java_aconfig_library {
+    name: "device_policy_aconfig_flags_java_export",
+    aconfig_declarations: "device_policy_aconfig_flags",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+    mode: "exported",
+    min_sdk_version: "30",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.permission",
+    ],
+}
+
+java_aconfig_library {
     name: "device_policy_aconfig_flags_lib_host",
     aconfig_declarations: "device_policy_aconfig_flags",
     host_supported: true,
@@ -1651,13 +1678,6 @@
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
-// Ranging
-java_aconfig_library {
-    name: "com.android.ranging.flags.ranging-aconfig-java",
-    aconfig_declarations: "ranging_aconfig_flags",
-    defaults: ["framework-minus-apex-aconfig-java-defaults"],
-}
-
 // System Server
 aconfig_declarations {
     name: "android.systemserver.flags-aconfig",
diff --git a/Android.bp b/Android.bp
index 49a6a2b..42028e0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -83,7 +83,6 @@
         ":framework-telecomm-sources",
         ":framework-telephony-common-sources",
         ":framework-telephony-sources",
-        ":framework-vcn-util-sources",
         ":framework-wifi-annotations",
         ":framework-wifi-non-updatable-sources",
         ":PacProcessor-aidl-sources",
@@ -313,7 +312,6 @@
             ":framework-telecomm-sources",
             ":framework-telephony-common-sources",
             ":framework-telephony-sources",
-            ":framework-vcn-util-sources",
             ":framework-wifi-annotations",
             ":framework-wifi-non-updatable-sources",
             ":PacProcessor-aidl-sources",
@@ -371,6 +369,7 @@
         "view-inspector-annotation-processor",
         "staledataclass-annotation-processor",
         "error_prone_android_framework",
+        "systemfeatures-metadata-processor",
     ],
     // Exports needed for staledataclass-annotation-processor, see b/139342589.
     javacflags: [
@@ -397,6 +396,8 @@
         "ext",
         "framework-updatable-stubs-module_libs_api",
         "unsupportedappusage",
+        // TODO(b/379770939): remove prod version of flags from other containers in framework
+        "aconfig_storage_stub",
     ],
     sdk_version: "core_platform",
     static_libs: [
@@ -595,7 +596,7 @@
     srcs: [
         "core/java/com/android/internal/util/HexDump.java",
         "core/java/com/android/internal/util/WakeupMessage.java",
-        "services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java",
+        "core/java/android/net/vcn/util/PersistableBundleUtils.java",
         "telephony/java/android/telephony/Annotation.java",
     ],
 }
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index a92a543..d748a3b 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -18,7 +18,7 @@
                tests/
                tools/
 bpfmt = -d
-ktfmt = --kotlinlang-style --include-dirs=services/permission,packages/SystemUI,libs/WindowManager/Shell/src/com/android/wm/shell/freeform
+ktfmt = --kotlinlang-style --include-dirs=services/permission,packages/SystemUI,libs/WindowManager/Shell/src/com/android/wm/shell/freeform,libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education
 
 [Hook Scripts]
 checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
diff --git a/android-sdk-flags/Android.bp b/android-sdk-flags/Android.bp
index 79a0b9a..d1df2ca 100644
--- a/android-sdk-flags/Android.bp
+++ b/android-sdk-flags/Android.bp
@@ -17,14 +17,21 @@
 }
 
 aconfig_declarations {
-    name: "android-sdk-flags",
+    name: "android.sdk.flags-aconfig",
     package: "android.sdk",
     container: "system",
     srcs: ["flags.aconfig"],
 }
 
 java_aconfig_library {
-    name: "android-sdk-flags-java",
-    aconfig_declarations: "android-sdk-flags",
+    name: "android.sdk.flags-aconfig-java",
+    aconfig_declarations: "android.sdk.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+java_aconfig_library {
+    name: "android.sdk.flags-aconfig-java-host",
+    aconfig_declarations: "android.sdk.flags-aconfig",
+    host_supported: true,
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
diff --git a/apct-tests/perftests/tracing/src/com/android/internal/protolog/ProtoLogPerfTest.java b/apct-tests/perftests/tracing/src/com/android/internal/protolog/ProtoLogPerfTest.java
index 7ef8c53..7168fbe 100644
--- a/apct-tests/perftests/tracing/src/com/android/internal/protolog/ProtoLogPerfTest.java
+++ b/apct-tests/perftests/tracing/src/com/android/internal/protolog/ProtoLogPerfTest.java
@@ -19,6 +19,9 @@
 import android.os.Bundle;
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.perftests.utils.Stats;
+import android.tracing.perfetto.DataSourceParams;
+import android.tracing.perfetto.InitArguments;
+import android.tracing.perfetto.Producer;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -70,6 +73,8 @@
     }
 
     private IProtoLog mProcessedProtoLogger;
+    private static ProtoLogDataSource sTestDataSource;
+    private static final String TEST_PROTOLOG_DATASOURCE_NAME = "test.android.protolog";
     private static final String MOCK_TEST_FILE_PATH = "mock/file/path";
     private static final perfetto.protos.Protolog.ProtoLogViewerConfig VIEWER_CONFIG =
             perfetto.protos.Protolog.ProtoLogViewerConfig.newBuilder()
@@ -89,6 +94,17 @@
 
     @BeforeClass
     public static void init() {
+        Producer.init(InitArguments.DEFAULTS);
+
+        sTestDataSource = new ProtoLogDataSource(TEST_PROTOLOG_DATASOURCE_NAME);
+        DataSourceParams params =
+                new DataSourceParams.Builder()
+                        .setBufferExhaustedPolicy(
+                                DataSourceParams
+                                        .PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP)
+                        .build();
+        sTestDataSource.register(params);
+
         ProtoLog.init(TestProtoLogGroup.values());
     }
 
@@ -98,9 +114,10 @@
         TestProtoLogGroup.TEST_GROUP.setLogToLogcat(mLogToLogcat);
 
         mProcessedProtoLogger = new ProcessedPerfettoProtoLogImpl(
+                sTestDataSource,
                 MOCK_TEST_FILE_PATH,
                 () -> new AutoClosableProtoInputStream(VIEWER_CONFIG.toByteArray()),
-                () -> {},
+                (instance) -> {},
                 TestProtoLogGroup.values()
         );
     }
diff --git a/apex/jobscheduler/service/aconfig/app_idle.aconfig b/apex/jobscheduler/service/aconfig/app_idle.aconfig
index f079c02..74d2a59 100644
--- a/apex/jobscheduler/service/aconfig/app_idle.aconfig
+++ b/apex/jobscheduler/service/aconfig/app_idle.aconfig
@@ -21,3 +21,10 @@
        purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "adjust_default_bucket_elevation_params"
+    namespace: "backstage_power"
+    description: "Adjust the default bucket evaluation parameters"
+    bug: "379909479"
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 963307b..a5a08fb 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -573,6 +573,7 @@
                         case Constants.KEY_MIN_LINEAR_BACKOFF_TIME_MS:
                         case Constants.KEY_MIN_EXP_BACKOFF_TIME_MS:
                         case Constants.KEY_SYSTEM_STOP_TO_FAILURE_RATIO:
+                        case Constants.KEY_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF:
                             mConstants.updateBackoffConstantsLocked();
                             break;
                         case Constants.KEY_CONN_CONGESTION_DELAY_FRAC:
@@ -679,6 +680,8 @@
         private static final String KEY_MIN_EXP_BACKOFF_TIME_MS = "min_exp_backoff_time_ms";
         private static final String KEY_SYSTEM_STOP_TO_FAILURE_RATIO =
                 "system_stop_to_failure_ratio";
+        private static final String KEY_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF =
+                "abandoned_job_timeouts_before_aggressive_backoff";
         private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac";
         private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac";
         private static final String KEY_CONN_USE_CELL_SIGNAL_STRENGTH =
@@ -750,6 +753,7 @@
         private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME_MS = JobInfo.MIN_BACKOFF_MILLIS;
         private static final long DEFAULT_MIN_EXP_BACKOFF_TIME_MS = JobInfo.MIN_BACKOFF_MILLIS;
         private static final int DEFAULT_SYSTEM_STOP_TO_FAILURE_RATIO = 3;
+        private static final int DEFAULT_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF = 3;
         private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
         private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f;
         private static final boolean DEFAULT_CONN_USE_CELL_SIGNAL_STRENGTH = true;
@@ -845,7 +849,12 @@
          * incremental failure in the backoff policy calculation.
          */
         int SYSTEM_STOP_TO_FAILURE_RATIO = DEFAULT_SYSTEM_STOP_TO_FAILURE_RATIO;
-
+        /**
+         * Number of consecutive timeouts by abandoned jobs before we change to aggressive backoff
+         * policy.
+         */
+        int ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF =
+                DEFAULT_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF;
         /**
          * The fraction of a job's running window that must pass before we
          * consider running it when the network is congested.
@@ -1078,6 +1087,10 @@
             SYSTEM_STOP_TO_FAILURE_RATIO = DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
                     KEY_SYSTEM_STOP_TO_FAILURE_RATIO,
                     DEFAULT_SYSTEM_STOP_TO_FAILURE_RATIO);
+            ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF = DeviceConfig.getInt(
+                    DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+                    KEY_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF,
+                    DEFAULT_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF);
         }
 
         // TODO(141645789): move into ConnectivityController.CcConfig
@@ -1287,6 +1300,8 @@
             pw.print(KEY_MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME_MS).println();
             pw.print(KEY_MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME_MS).println();
             pw.print(KEY_SYSTEM_STOP_TO_FAILURE_RATIO, SYSTEM_STOP_TO_FAILURE_RATIO).println();
+            pw.print(KEY_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF,
+                    ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF).println();
             pw.print(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println();
             pw.print(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println();
             pw.print(KEY_CONN_USE_CELL_SIGNAL_STRENGTH, CONN_USE_CELL_SIGNAL_STRENGTH).println();
@@ -2997,6 +3012,7 @@
 
         final long initialBackoffMillis = job.getInitialBackoffMillis();
         int numFailures = failureToReschedule.getNumFailures();
+        int numAbandonedFailures = failureToReschedule.getNumAbandonedFailures();
         int numSystemStops = failureToReschedule.getNumSystemStops();
         // We should back off slowly if JobScheduler keeps stopping the job,
         // but back off immediately if the issue appeared to be the app's fault
@@ -3006,9 +3022,19 @@
                 || internalStopReason == JobParameters.INTERNAL_STOP_REASON_ANR
                 || stopReason == JobParameters.STOP_REASON_USER) {
             numFailures++;
+        } else if (android.app.job.Flags.handleAbandonedJobs()
+                && internalStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT_ABANDONED) {
+            numAbandonedFailures++;
+            numFailures++;
         } else {
             numSystemStops++;
         }
+
+        int backoffPolicy = job.getBackoffPolicy();
+        if (shouldUseAggressiveBackoff(numAbandonedFailures)) {
+            backoffPolicy = JobInfo.BACKOFF_POLICY_EXPONENTIAL;
+        }
+
         final int backoffAttempts =
                 numFailures + numSystemStops / mConstants.SYSTEM_STOP_TO_FAILURE_RATIO;
         final long earliestRuntimeMs;
@@ -3017,7 +3043,7 @@
             earliestRuntimeMs = JobStatus.NO_EARLIEST_RUNTIME;
         } else {
             long delayMillis;
-            switch (job.getBackoffPolicy()) {
+            switch (backoffPolicy) {
                 case JobInfo.BACKOFF_POLICY_LINEAR: {
                     long backoff = initialBackoffMillis;
                     if (backoff < mConstants.MIN_LINEAR_BACKOFF_TIME_MS) {
@@ -3046,7 +3072,7 @@
         }
         JobStatus newJob = new JobStatus(failureToReschedule,
                 earliestRuntimeMs,
-                JobStatus.NO_LATEST_RUNTIME, numFailures, numSystemStops,
+                JobStatus.NO_LATEST_RUNTIME, numFailures, numAbandonedFailures, numSystemStops,
                 failureToReschedule.getLastSuccessfulRunTime(), sSystemClock.millis(),
                 failureToReschedule.getCumulativeExecutionTimeMs());
         if (stopReason == JobParameters.STOP_REASON_USER) {
@@ -3069,6 +3095,20 @@
     }
 
     /**
+     * Returns {@code true} if the given number of abandoned failures indicates that JobScheduler
+     * should use an aggressive backoff policy.
+     *
+     * @param numAbandonedFailures The number of abandoned failures.
+     * @return {@code true} if the given number of abandoned failures indicates that JobScheduler
+     *     should use an aggressive backoff policy.
+     */
+    public boolean shouldUseAggressiveBackoff(int numAbandonedFailures) {
+        return android.app.job.Flags.handleAbandonedJobs()
+                && numAbandonedFailures
+                        > mConstants.ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF;
+    }
+
+    /**
      * Maximum time buffer in which JobScheduler will try to optimize periodic job scheduling. This
      * does not cause a job's period to be larger than requested (eg: if the requested period is
      * shorter than this buffer). This is used to put a limit on when JobScheduler will intervene
@@ -3147,6 +3187,7 @@
             return new JobStatus(periodicToReschedule,
                     elapsedNow + period - flex, elapsedNow + period,
                     0 /* numFailures */, 0 /* numSystemStops */,
+                    0 /* numAbandonedFailures */,
                     sSystemClock.millis() /* lastSuccessfulRunTime */,
                     periodicToReschedule.getLastFailedRunTime(),
                     0 /* Reset cumulativeExecutionTime because of successful execution */);
@@ -3163,6 +3204,7 @@
         return new JobStatus(periodicToReschedule,
                 newEarliestRunTimeElapsed, newLatestRuntimeElapsed,
                 0 /* numFailures */, 0 /* numSystemStops */,
+                0 /* numAbandonedFailures */,
                 sSystemClock.millis() /* lastSuccessfulRunTime */,
                 periodicToReschedule.getLastFailedRunTime(),
                 0 /* Reset cumulativeExecutionTime because of successful execution */);
@@ -3171,6 +3213,10 @@
     @VisibleForTesting
     void maybeProcessBuggyJob(@NonNull JobStatus jobStatus, int debugStopReason) {
         boolean jobTimedOut = debugStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT;
+        if (android.app.job.Flags.handleAbandonedJobs()) {
+            jobTimedOut |= (debugStopReason
+                == JobParameters.INTERNAL_STOP_REASON_TIMEOUT_ABANDONED);
+        }
         // If madeActive = 0, the job never actually started.
         if (!jobTimedOut && jobStatus.madeActive > 0) {
             final long executionDurationMs = sUptimeMillisClock.millis() - jobStatus.madeActive;
@@ -3252,9 +3298,12 @@
         // we stop it.
         final JobStatus rescheduledJob = needsReschedule
                 ? getRescheduleJobForFailureLocked(jobStatus, stopReason, debugStopReason) : null;
+        final boolean isStopReasonAbandoned = android.app.job.Flags.handleAbandonedJobs()
+                && (debugStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT_ABANDONED);
         if (rescheduledJob != null
                 && !rescheduledJob.shouldTreatAsUserInitiatedJob()
                 && (debugStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT
+                || isStopReasonAbandoned
                 || debugStopReason == JobParameters.INTERNAL_STOP_REASON_PREEMPT)) {
             rescheduledJob.disallowRunInBatterySaverAndDoze();
         }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index d8934d8..dfb3681 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -269,7 +269,9 @@
                         convertRtcBoundsToElapsed(utcTimes, elapsedNow);
                 JobStatus newJob = new JobStatus(job,
                         elapsedRuntimes.first, elapsedRuntimes.second,
-                        0, 0, job.getLastSuccessfulRunTime(), job.getLastFailedRunTime(),
+                        0 /* numFailures */, 0 /* numAbandonedFailures */,
+                        0 /* numSystemStops */, job.getLastSuccessfulRunTime(),
+                        job.getLastFailedRunTime(),
                         job.getCumulativeExecutionTimeMs());
                 newJob.prepareLocked();
                 toAdd.add(newJob);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index a3eaefd..5a33aa0 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -316,6 +316,12 @@
     private final int numFailures;
 
     /**
+     * How many times this job has stopped due to {@link
+     * JobParameters#STOP_REASON_TIMEOUT_ABANDONED}.
+     */
+    private final int mNumAbandonedFailures;
+
+    /**
      * The number of times JobScheduler has forced this job to stop due to reasons mostly outside
      * of the app's control.
      */
@@ -605,6 +611,8 @@
      * @param tag A string associated with the job for debugging/logging purposes.
      * @param numFailures Count of how many times this job has requested a reschedule because
      *     its work was not yet finished.
+     * @param mNumAbandonedFailures Count of how many times this job has requested a reschedule
+     *     because it was abandoned.
      * @param numSystemStops Count of how many times JobScheduler has forced this job to stop due to
      *     factors mostly out of the app's control.
      * @param earliestRunTimeElapsedMillis Milestone: earliest point in time at which the job
@@ -617,7 +625,7 @@
      */
     private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
             int sourceUserId, int standbyBucket, @Nullable String namespace, String tag,
-            int numFailures, int numSystemStops,
+            int numFailures, int mNumAbandonedFailures, int numSystemStops,
             long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
             long lastSuccessfulRunTime, long lastFailedRunTime, long cumulativeExecutionTimeMs,
             int internalFlags,
@@ -677,6 +685,7 @@
         this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
         this.mOriginalLatestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
         this.numFailures = numFailures;
+        this.mNumAbandonedFailures = mNumAbandonedFailures;
         mNumSystemStops = numSystemStops;
 
         int requiredConstraints = job.getConstraintFlags();
@@ -750,7 +759,8 @@
         this(jobStatus.getJob(), jobStatus.getUid(),
                 jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
                 jobStatus.getStandbyBucket(), jobStatus.getNamespace(),
-                jobStatus.getSourceTag(), jobStatus.getNumFailures(), jobStatus.getNumSystemStops(),
+                jobStatus.getSourceTag(), jobStatus.getNumFailures(),
+                jobStatus.getNumAbandonedFailures(), jobStatus.getNumSystemStops(),
                 jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(),
                 jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime(),
                 jobStatus.getCumulativeExecutionTimeMs(),
@@ -787,6 +797,7 @@
         this(job, callingUid, sourcePkgName, sourceUserId,
                 standbyBucket, namespace,
                 sourceTag, /* numFailures */ 0, /* numSystemStops */ 0,
+                /* mNumAbandonedFailures */ 0,
                 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
                 lastSuccessfulRunTime, lastFailedRunTime, cumulativeExecutionTimeMs,
                 innerFlags, dynamicConstraints);
@@ -806,13 +817,15 @@
     /** Create a new job to be rescheduled with the provided parameters. */
     public JobStatus(JobStatus rescheduling,
             long newEarliestRuntimeElapsedMillis,
-            long newLatestRuntimeElapsedMillis, int numFailures, int numSystemStops,
+            long newLatestRuntimeElapsedMillis, int numFailures,
+            int mNumAbandonedFailures, int numSystemStops,
             long lastSuccessfulRunTime, long lastFailedRunTime,
             long cumulativeExecutionTimeMs) {
         this(rescheduling.job, rescheduling.getUid(),
                 rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
                 rescheduling.getStandbyBucket(), rescheduling.getNamespace(),
-                rescheduling.getSourceTag(), numFailures, numSystemStops,
+                rescheduling.getSourceTag(), numFailures,
+                mNumAbandonedFailures, numSystemStops,
                 newEarliestRuntimeElapsedMillis,
                 newLatestRuntimeElapsedMillis,
                 lastSuccessfulRunTime, lastFailedRunTime, cumulativeExecutionTimeMs,
@@ -851,7 +864,8 @@
         int standbyBucket = JobSchedulerService.standbyBucketForPackage(jobPackage,
                 sourceUserId, elapsedNow);
         return new JobStatus(job, callingUid, sourcePkg, sourceUserId,
-                standbyBucket, namespace, tag, /* numFailures */ 0, /* numSystemStops */ 0,
+                standbyBucket, namespace, tag, /* numFailures */ 0,
+                /* mNumAbandonedFailures */ 0, /* numSystemStops */ 0,
                 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
                 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */,
                 /* cumulativeExecutionTime */ 0,
@@ -1146,6 +1160,13 @@
     }
 
     /**
+     * Returns the number of times the job stopped previously for STOP_REASON_TIMEOUT_ABANDONED.
+     */
+    public int getNumAbandonedFailures() {
+        return mNumAbandonedFailures;
+    }
+
+    /**
      * Returns the number of times the system stopped a previous execution of this job for reasons
      * that were likely outside the app's control.
      */
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 c9d3407..9871d71 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -337,11 +337,11 @@
      */
     long[] mAppStandbyElapsedThresholds = DEFAULT_ELAPSED_TIME_THRESHOLDS;
     /** Minimum time a strong usage event should keep the bucket elevated. */
-    long mStrongUsageTimeoutMillis = ConstantsObserver.DEFAULT_STRONG_USAGE_TIMEOUT;
+    long mStrongUsageTimeoutMillis = ConstantsObserver.DEFAULT_LEGACY_STRONG_USAGE_TIMEOUT;
     /** Minimum time a notification seen event should keep the bucket elevated. */
     long mNotificationSeenTimeoutMillis = ConstantsObserver.DEFAULT_NOTIFICATION_TIMEOUT;
     /** Minimum time a slice pinned event should keep the bucket elevated. */
-    long mSlicePinnedTimeoutMillis = ConstantsObserver.DEFAULT_SLICE_PINNED_TIMEOUT;
+    long mSlicePinnedTimeoutMillis = ConstantsObserver.DEFAULT_LEGACY_SLICE_PINNED_TIMEOUT;
     /** The standby bucket that an app will be promoted on a notification-seen event */
     int mNotificationSeenPromotedBucket =
             ConstantsObserver.DEFAULT_NOTIFICATION_SEEN_PROMOTED_BUCKET;
@@ -362,7 +362,9 @@
     /** Maximum time to wait for a prediction before using simple timeouts to downgrade buckets. */
     long mPredictionTimeoutMillis = DEFAULT_PREDICTION_TIMEOUT;
     /** Maximum time a sync adapter associated with a CP should keep the buckets elevated. */
-    long mSyncAdapterTimeoutMillis = ConstantsObserver.DEFAULT_SYNC_ADAPTER_TIMEOUT;
+    long mSyncAdapterTimeoutMillis = ConstantsObserver.DEFAULT_LEGACY_SYNC_ADAPTER_TIMEOUT;
+    /** The bucket that an app will be promoted on a sync adapter associated with a CP */
+    int mSyncAdapaterPromotedBucket = STANDBY_BUCKET_ACTIVE;
     /**
      * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in
      * non-doze
@@ -751,7 +753,7 @@
                         userId);
                 synchronized (mAppIdleLock) {
                     reportNoninteractiveUsageCrossUserLocked(packageName, userId,
-                            STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_SYNC_ADAPTER,
+                            mSyncAdapaterPromotedBucket, REASON_SUB_USAGE_SYNC_ADAPTER,
                             elapsedRealtime, mSyncAdapterTimeoutMillis, linkedProfiles);
                 }
             }
@@ -2446,6 +2448,8 @@
         pw.println("Flags: ");
         pw.println("    " + Flags.FLAG_AVOID_IDLE_CHECK
                 + ": " + Flags.avoidIdleCheck());
+        pw.println("    " + Flags.FLAG_ADJUST_DEFAULT_BUCKET_ELEVATION_PARAMS
+                + ": " + Flags.adjustDefaultBucketElevationParams());
         pw.println();
 
         synchronized (mCarrierPrivilegedLock) {
@@ -2481,6 +2485,9 @@
         pw.print("  mSyncAdapterTimeoutMillis=");
         TimeUtils.formatDuration(mSyncAdapterTimeoutMillis, pw);
         pw.println();
+        pw.print("  mSyncAdapaterPromotedBucket=");
+        pw.print(standbyBucketToString(mSyncAdapaterPromotedBucket));
+        pw.println();
         pw.print("  mSystemInteractionTimeoutMillis=");
         TimeUtils.formatDuration(mSystemInteractionTimeoutMillis, pw);
         pw.println();
@@ -3059,12 +3066,18 @@
 
         public static final long DEFAULT_CHECK_IDLE_INTERVAL_MS =
                 COMPRESS_TIME ? ONE_MINUTE : 4 * ONE_HOUR;
-        public static final long DEFAULT_STRONG_USAGE_TIMEOUT =
+        public static final long DEFAULT_LEGACY_STRONG_USAGE_TIMEOUT =
                 COMPRESS_TIME ? ONE_MINUTE : 1 * ONE_HOUR;
+
+        public static final long DEFAULT_CURRENT_STRONG_USAGE_TIMEOUT =
+                COMPRESS_TIME ? ONE_MINUTE : 5 * ONE_MINUTE;
         public static final long DEFAULT_NOTIFICATION_TIMEOUT =
                 COMPRESS_TIME ? 12 * ONE_MINUTE : 12 * ONE_HOUR;
-        public static final long DEFAULT_SLICE_PINNED_TIMEOUT =
+        public static final long DEFAULT_LEGACY_SLICE_PINNED_TIMEOUT =
                 COMPRESS_TIME ? 12 * ONE_MINUTE : 12 * ONE_HOUR;
+
+        public static final long DEFAULT_CURRENT_SLICE_PINNED_TIMEOUT =
+                COMPRESS_TIME ? 12 * ONE_MINUTE : 2 * ONE_HOUR;
         public static final int DEFAULT_NOTIFICATION_SEEN_PROMOTED_BUCKET =
                 STANDBY_BUCKET_WORKING_SET;
         public static final boolean DEFAULT_RETAIN_NOTIFICATION_SEEN_IMPACT_FOR_PRE_T_APPS = false;
@@ -3073,8 +3086,11 @@
                 COMPRESS_TIME ? 2 * ONE_MINUTE : 2 * ONE_HOUR;
         public static final long DEFAULT_SYSTEM_INTERACTION_TIMEOUT =
                 COMPRESS_TIME ? ONE_MINUTE : 10 * ONE_MINUTE;
-        public static final long DEFAULT_SYNC_ADAPTER_TIMEOUT =
+        public static final long DEFAULT_LEGACY_SYNC_ADAPTER_TIMEOUT =
                 COMPRESS_TIME ? ONE_MINUTE : 10 * ONE_MINUTE;
+
+        public static final long DEFAULT_CURRENT_SYNC_ADAPTER_TIMEOUT =
+                COMPRESS_TIME ? ONE_MINUTE : 2 * ONE_HOUR;
         public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT =
                 COMPRESS_TIME ? (ONE_MINUTE / 2) : 10 * ONE_MINUTE;
         public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT =
@@ -3117,6 +3133,9 @@
             cr.registerContentObserver(Global.getUriFor(Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED),
                     false, this);
             mInjector.registerDeviceConfigPropertiesChangedListener(this);
+
+            processDefaultConstants();
+
             // Load all the constants.
             // postOneTimeCheckIdleStates() doesn't need to be called on boot.
             processProperties(mInjector.getDeviceConfigProperties());
@@ -3135,6 +3154,17 @@
             postOneTimeCheckIdleStates();
         }
 
+        private void processDefaultConstants() {
+            if (!Flags.adjustDefaultBucketElevationParams()) {
+                return;
+            }
+
+            mSlicePinnedTimeoutMillis = DEFAULT_CURRENT_SLICE_PINNED_TIMEOUT;
+            mSyncAdapterTimeoutMillis = DEFAULT_CURRENT_SYNC_ADAPTER_TIMEOUT;
+            mSyncAdapaterPromotedBucket = STANDBY_BUCKET_WORKING_SET;
+            mStrongUsageTimeoutMillis = DEFAULT_CURRENT_STRONG_USAGE_TIMEOUT;
+        }
+
         private void processProperties(DeviceConfig.Properties properties) {
             boolean timeThresholdsUpdated = false;
             synchronized (mAppIdleLock) {
@@ -3182,11 +3212,16 @@
                         case KEY_SLICE_PINNED_HOLD_DURATION:
                             mSlicePinnedTimeoutMillis = properties.getLong(
                                     KEY_SLICE_PINNED_HOLD_DURATION,
-                                    DEFAULT_SLICE_PINNED_TIMEOUT);
+                                    Flags.adjustDefaultBucketElevationParams()
+                                            ? DEFAULT_CURRENT_SLICE_PINNED_TIMEOUT
+                                            : DEFAULT_LEGACY_SLICE_PINNED_TIMEOUT);
                             break;
                         case KEY_STRONG_USAGE_HOLD_DURATION:
                             mStrongUsageTimeoutMillis = properties.getLong(
-                                    KEY_STRONG_USAGE_HOLD_DURATION, DEFAULT_STRONG_USAGE_TIMEOUT);
+                                    KEY_STRONG_USAGE_HOLD_DURATION,
+                                    Flags.adjustDefaultBucketElevationParams()
+                                            ? DEFAULT_CURRENT_STRONG_USAGE_TIMEOUT
+                                            : DEFAULT_LEGACY_STRONG_USAGE_TIMEOUT);
                             break;
                         case KEY_PREDICTION_TIMEOUT:
                             mPredictionTimeoutMillis = properties.getLong(
@@ -3203,7 +3238,10 @@
                             break;
                         case KEY_SYNC_ADAPTER_HOLD_DURATION:
                             mSyncAdapterTimeoutMillis = properties.getLong(
-                                    KEY_SYNC_ADAPTER_HOLD_DURATION, DEFAULT_SYNC_ADAPTER_TIMEOUT);
+                                    KEY_SYNC_ADAPTER_HOLD_DURATION,
+                                    Flags.adjustDefaultBucketElevationParams()
+                                            ? DEFAULT_CURRENT_SYNC_ADAPTER_TIMEOUT
+                                            : DEFAULT_LEGACY_SYNC_ADAPTER_TIMEOUT);
                             break;
                         case KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION:
                             mExemptedSyncScheduledDozeTimeoutMillis = properties.getLong(
diff --git a/boot/boot-image-profile-extra.txt b/boot/boot-image-profile-extra.txt
index e31eb3a..fd51f9c 100644
--- a/boot/boot-image-profile-extra.txt
+++ b/boot/boot-image-profile-extra.txt
@@ -23,4 +23,25 @@
 # For now, compile all methods in MessageQueue to avoid performance cliffs for
 # flagged/evolving hot code paths. See: b/338098106
 HSPLandroid/os/MessageQueue;->*
-HSPLandroid/os/MessageQueue$*;->*
+HSPLandroid/os/MessageQueue$FileDescriptorRecord;->*
+HSPLandroid/os/MessageQueue$IdleHandler;->*
+HSPLandroid/os/MessageQueue$MessageCompare;->*
+HSPLandroid/os/MessageQueue$MatchAllFutureMessages;->*
+HSPLandroid/os/MessageQueue$MatchAllMessages;->*
+HSPLandroid/os/MessageQueue$MatchBarrierToken;->*
+HSPLandroid/os/MessageQueue$MatchDeliverableMessages;->*
+HSPLandroid/os/MessageQueue$MatchHandler;->*
+HSPLandroid/os/MessageQueue$MatchHandlerAndObject;->*
+HSPLandroid/os/MessageQueue$MatchHandlerAndObjectEquals;->*
+HSPLandroid/os/MessageQueue$MatchHandlerRunnableAndObject;->*
+HSPLandroid/os/MessageQueue$MatchHandlerRunnableAndObjectEquals;->*
+HSPLandroid/os/MessageQueue$MatchHandlerWhatAndObject;->*
+HSPLandroid/os/MessageQueue$MatchHandlerWhatAndObjectEquals;->*
+HSPLandroid/os/MessageQueue$MessageCounts;->*
+HSPLandroid/os/MessageQueue$StackNode;->*
+HSPLandroid/os/MessageQueue$MessageNode;->*
+HSPLandroid/os/MessageQueue$OnFileDescriptorEventListener$Events;->*
+HSPLandroid/os/MessageQueue$OnFileDescriptorEventListener;->*
+HSPLandroid/os/MessageQueue$StackNodeType;->*
+HSPLandroid/os/MessageQueue$StateNode;->*
+HSPLandroid/os/MessageQueue$TimedParkStateNode;->*
diff --git a/cmds/idmap2/idmap2/CreateMultiple.cpp b/cmds/idmap2/idmap2/CreateMultiple.cpp
index 68800cd..2608c69 100644
--- a/cmds/idmap2/idmap2/CreateMultiple.cpp
+++ b/cmds/idmap2/idmap2/CreateMultiple.cpp
@@ -99,7 +99,7 @@
 
   std::vector<std::string> idmap_paths;
   for (const std::string& overlay_apk_path : overlay_apk_paths) {
-    const std::string idmap_path = Idmap::CanonicalIdmapPathFor(idmap_dir, overlay_apk_path);
+    std::string idmap_path = Idmap::CanonicalIdmapPathFor(idmap_dir, overlay_apk_path);
     const uid_t uid = getuid();
     if (!UidHasWriteAccessToPath(uid, idmap_path)) {
       LOG(WARNING) << "uid " << uid << "does not have write access to " << idmap_path.c_str();
@@ -111,7 +111,7 @@
                 !ignore_overlayable)) {
       const auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
       if (!overlay) {
-        LOG(WARNING) << "failed to load apk " << overlay_apk_path.c_str();
+        LOG(WARNING) << "failed to load apk " << overlay_apk_path;
         continue;
       }
 
@@ -138,7 +138,7 @@
       }
     }
 
-    idmap_paths.emplace_back(idmap_path);
+    idmap_paths.emplace_back(std::move(idmap_path));
   }
 
   for (const std::string& idmap_path : idmap_paths) {
diff --git a/core/api/current.txt b/core/api/current.txt
index 8b17908..4a1628e 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1203,6 +1203,7 @@
     field public static final int minResizeHeight = 16843670; // 0x1010396
     field public static final int minResizeWidth = 16843669; // 0x1010395
     field public static final int minSdkVersion = 16843276; // 0x101020c
+    field @FlaggedApi("android.content.pm.support_minor_versions_in_minsdkversion") public static final int minSdkVersionFull;
     field public static final int minWidth = 16843071; // 0x101013f
     field public static final int minimumHorizontalAngle = 16843901; // 0x101047d
     field public static final int minimumVerticalAngle = 16843902; // 0x101047e
@@ -1502,6 +1503,7 @@
     field public static final int shadowRadius = 16843108; // 0x1010164
     field public static final int shape = 16843162; // 0x101019a
     field public static final int shareInterpolator = 16843195; // 0x10101bb
+    field @FlaggedApi("android.nfc.nfc_associated_role_services") public static final int shareRolePriority;
     field @Deprecated public static final int sharedUserId = 16842763; // 0x101000b
     field @Deprecated public static final int sharedUserLabel = 16843361; // 0x1010261
     field public static final int sharedUserMaxSdkVersion = 16844365; // 0x101064d
@@ -2451,6 +2453,7 @@
     field public static final int primary = 16908300; // 0x102000c
     field public static final int progress = 16908301; // 0x102000d
     field public static final int redo = 16908339; // 0x1020033
+    field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final int remoteViewsMetricsId;
     field public static final int replaceText = 16908340; // 0x1020034
     field public static final int secondaryProgress = 16908303; // 0x102000f
     field public static final int selectAll = 16908319; // 0x102001f
@@ -9892,6 +9895,8 @@
     field public static final String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK";
     field public static final String ACTION_APPWIDGET_RESTORED = "android.appwidget.action.APPWIDGET_RESTORED";
     field public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
+    field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final String EVENT_CATEGORY_APPWIDGET = "android.appwidget";
+    field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final String EVENT_TYPE_WIDGET_INTERACTION = "widget_interaction";
     field public static final String EXTRA_APPWIDGET_ID = "appWidgetId";
     field public static final String EXTRA_APPWIDGET_IDS = "appWidgetIds";
     field public static final String EXTRA_APPWIDGET_OLD_IDS = "appWidgetOldIds";
@@ -9901,6 +9906,10 @@
     field public static final String EXTRA_APPWIDGET_PROVIDER_PROFILE = "appWidgetProviderProfile";
     field public static final String EXTRA_CUSTOM_EXTRAS = "customExtras";
     field public static final String EXTRA_CUSTOM_INFO = "customInfo";
+    field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final String EXTRA_EVENT_CLICKED_VIEWS = "android.appwidget.extra.EVENT_CLICKED_VIEWS";
+    field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final String EXTRA_EVENT_DURATION_MS = "android.appwidget.extra.EVENT_DURATION_MS";
+    field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final String EXTRA_EVENT_POSITION_RECT = "android.appwidget.extra.EVENT_POSITION_RECT";
+    field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final String EXTRA_EVENT_SCROLLED_VIEWS = "android.appwidget.extra.EVENT_SCROLLED_VIEWS";
     field public static final String EXTRA_HOST_ID = "hostId";
     field public static final int INVALID_APPWIDGET_ID = 0; // 0x0
     field public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider";
@@ -10081,10 +10090,10 @@
     method @FlaggedApi("android.companion.unpair_associated_device") @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean removeBond(int);
     method public void requestNotificationAccess(android.content.ComponentName);
     method @FlaggedApi("android.companion.association_tag") public void setAssociationTag(int, @NonNull String);
-    method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void startObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException;
+    method @Deprecated @FlaggedApi("android.companion.device_presence") @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void startObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException;
     method @FlaggedApi("android.companion.device_presence") @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void startObservingDevicePresence(@NonNull android.companion.ObservingDevicePresenceRequest);
     method public void startSystemDataTransfer(int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.companion.CompanionException>) throws android.companion.DeviceNotAssociatedException;
-    method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void stopObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException;
+    method @Deprecated @FlaggedApi("android.companion.device_presence") @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void stopObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException;
     method @FlaggedApi("android.companion.device_presence") @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void stopObservingDevicePresence(@NonNull android.companion.ObservingDevicePresenceRequest);
     field public static final String EXTRA_ASSOCIATION = "android.companion.extra.ASSOCIATION";
     field @Deprecated public static final String EXTRA_DEVICE = "android.companion.extra.DEVICE";
@@ -10112,9 +10121,9 @@
     method @RequiresPermission(android.Manifest.permission.DELIVER_COMPANION_MESSAGES) public final void detachSystemDataTransport(int) throws android.companion.DeviceNotAssociatedException;
     method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
     method @Deprecated @MainThread public void onDeviceAppeared(@NonNull String);
-    method @MainThread public void onDeviceAppeared(@NonNull android.companion.AssociationInfo);
+    method @Deprecated @FlaggedApi("android.companion.device_presence") @MainThread public void onDeviceAppeared(@NonNull android.companion.AssociationInfo);
     method @Deprecated @MainThread public void onDeviceDisappeared(@NonNull String);
-    method @MainThread public void onDeviceDisappeared(@NonNull android.companion.AssociationInfo);
+    method @Deprecated @FlaggedApi("android.companion.device_presence") @MainThread public void onDeviceDisappeared(@NonNull android.companion.AssociationInfo);
     method @FlaggedApi("android.companion.device_presence") @MainThread public void onDevicePresenceEvent(@NonNull android.companion.DevicePresenceEvent);
     field public static final String SERVICE_INTERFACE = "android.companion.CompanionDeviceService";
   }
@@ -13146,9 +13155,9 @@
     method public void setAppLabel(@Nullable CharSequence);
     method public void setAppPackageName(@Nullable String);
     method public void setApplicationEnabledSettingPersistent();
+    method @FlaggedApi("android.content.pm.sdk_dependency_installer") public void setAutoInstallDependenciesEnabled(boolean);
     method @Deprecated public void setAutoRevokePermissionsMode(boolean);
     method public void setDontKillApp(boolean);
-    method @FlaggedApi("android.content.pm.sdk_dependency_installer") public void setEnableAutoInstallDependencies(boolean);
     method public void setInstallLocation(int);
     method public void setInstallReason(int);
     method public void setInstallScenario(int);
@@ -13217,8 +13226,8 @@
   public abstract class PackageManager {
     ctor @Deprecated public PackageManager();
     method @Deprecated public abstract void addPackageToPreferred(@NonNull String);
-    method public abstract boolean addPermission(@NonNull android.content.pm.PermissionInfo);
-    method public abstract boolean addPermissionAsync(@NonNull android.content.pm.PermissionInfo);
+    method @Deprecated @FlaggedApi("android.permission.flags.permission_tree_apis_deprecated") public abstract boolean addPermission(@NonNull android.content.pm.PermissionInfo);
+    method @Deprecated @FlaggedApi("android.permission.flags.permission_tree_apis_deprecated") public abstract boolean addPermissionAsync(@NonNull android.content.pm.PermissionInfo);
     method @Deprecated public abstract void addPreferredActivity(@NonNull android.content.IntentFilter, int, @Nullable android.content.ComponentName[], @NonNull android.content.ComponentName);
     method @RequiresPermission(value="android.permission.WHITELIST_RESTRICTED_PERMISSIONS", conditional=true) public boolean addWhitelistedRestrictedPermission(@NonNull String, @NonNull String, int);
     method public boolean canPackageQuery(@NonNull String, @NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -13359,7 +13368,7 @@
     method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryServiceProperty(@NonNull String);
     method public void relinquishUpdateOwnership(@NonNull String);
     method @Deprecated public abstract void removePackageFromPreferred(@NonNull String);
-    method public abstract void removePermission(@NonNull String);
+    method @Deprecated @FlaggedApi("android.permission.flags.permission_tree_apis_deprecated") public abstract void removePermission(@NonNull String);
     method @RequiresPermission(value="android.permission.WHITELIST_RESTRICTED_PERMISSIONS", conditional=true) public boolean removeWhitelistedRestrictedPermission(@NonNull String, @NonNull String, int);
     method public void requestChecksums(@NonNull String, boolean, int, @NonNull java.util.List<java.security.cert.Certificate>, @NonNull android.content.pm.PackageManager.OnChecksumsReadyListener) throws java.security.cert.CertificateEncodingException, android.content.pm.PackageManager.NameNotFoundException;
     method @Nullable public abstract android.content.pm.ResolveInfo resolveActivity(@NonNull android.content.Intent, int);
@@ -18954,6 +18963,7 @@
     method @FlaggedApi("android.hardware.flags.luts_api") @NonNull public int[] getSamplingKeys();
     method @FlaggedApi("android.hardware.flags.luts_api") public int getSize();
     field @FlaggedApi("android.hardware.flags.luts_api") public static final int ONE_DIMENSION = 1; // 0x1
+    field @FlaggedApi("android.hardware.flags.luts_api") public static final int SAMPLING_KEY_CIE_Y = 2; // 0x2
     field @FlaggedApi("android.hardware.flags.luts_api") public static final int SAMPLING_KEY_MAX_RGB = 1; // 0x1
     field @FlaggedApi("android.hardware.flags.luts_api") public static final int SAMPLING_KEY_RGB = 0; // 0x0
     field @FlaggedApi("android.hardware.flags.luts_api") public static final int THREE_DIMENSION = 3; // 0x3
@@ -20758,6 +20768,7 @@
 
   public final class VirtualDisplayConfig implements android.os.Parcelable {
     method public int describeContents();
+    method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @FloatRange(from=0.0f, to=1.0f) public float getDefaultBrightness();
     method public int getDensityDpi();
     method @NonNull public java.util.Set<java.lang.String> getDisplayCategories();
     method public int getFlags();
@@ -20770,10 +20781,16 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.hardware.display.VirtualDisplayConfig> CREATOR;
   }
 
+  @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") public static interface VirtualDisplayConfig.BrightnessListener {
+    method public void onBrightnessChanged(@FloatRange(from=0.0f, to=1.0f) float);
+  }
+
   public static final class VirtualDisplayConfig.Builder {
     ctor public VirtualDisplayConfig.Builder(@NonNull String, @IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int);
     method @NonNull public android.hardware.display.VirtualDisplayConfig.Builder addDisplayCategory(@NonNull String);
     method @NonNull public android.hardware.display.VirtualDisplayConfig build();
+    method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setBrightnessListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.display.VirtualDisplayConfig.BrightnessListener);
+    method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setDefaultBrightness(@FloatRange(from=0.0f, to=1.0f) float);
     method @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setDisplayCategories(@NonNull java.util.Set<java.lang.String>);
     method @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setFlags(int);
     method @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setRequestedRefreshRate(@FloatRange(from=0.0f) float);
@@ -24166,6 +24183,8 @@
     field public static final String KEY_OPERATING_RATE = "operating-rate";
     field public static final String KEY_OUTPUT_REORDER_DEPTH = "output-reorder-depth";
     field public static final String KEY_PCM_ENCODING = "pcm-encoding";
+    field @FlaggedApi("android.media.tv.flags.apply_picture_profiles") public static final String KEY_PICTURE_PROFILE_ID = "picture-profile-id";
+    field @FlaggedApi("android.media.tv.flags.apply_picture_profiles") public static final String KEY_PICTURE_PROFILE_INSTANCE = "picture-profile-instance";
     field public static final String KEY_PICTURE_TYPE = "picture-type";
     field public static final String KEY_PIXEL_ASPECT_RATIO_HEIGHT = "sar-height";
     field public static final String KEY_PIXEL_ASPECT_RATIO_WIDTH = "sar-width";
@@ -24842,6 +24861,7 @@
     method @NonNull public String getId();
     method @NonNull public CharSequence getName();
     method @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") public int getSuitabilityStatus();
+    method @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public int getSupportedRoutingTypes();
     method public int getType();
     method public int getVolume();
     method public int getVolumeHandling();
@@ -24857,6 +24877,8 @@
     field public static final String FEATURE_REMOTE_AUDIO_PLAYBACK = "android.media.route.feature.REMOTE_AUDIO_PLAYBACK";
     field public static final String FEATURE_REMOTE_PLAYBACK = "android.media.route.feature.REMOTE_PLAYBACK";
     field public static final String FEATURE_REMOTE_VIDEO_PLAYBACK = "android.media.route.feature.REMOTE_VIDEO_PLAYBACK";
+    field @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public static final int FLAG_ROUTING_TYPE_REMOTE = 4; // 0x4
+    field @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public static final int FLAG_ROUTING_TYPE_SYSTEM_AUDIO = 1; // 0x1
     field public static final int PLAYBACK_VOLUME_FIXED = 0; // 0x0
     field public static final int PLAYBACK_VOLUME_VARIABLE = 1; // 0x1
     field @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") public static final int SUITABILITY_STATUS_NOT_SUITABLE_FOR_TRANSFER = 2; // 0x2
@@ -24907,6 +24929,7 @@
     method @NonNull public android.media.MediaRoute2Info.Builder setExtras(@Nullable android.os.Bundle);
     method @NonNull public android.media.MediaRoute2Info.Builder setIconUri(@Nullable android.net.Uri);
     method @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") @NonNull public android.media.MediaRoute2Info.Builder setSuitabilityStatus(int);
+    method @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") @NonNull public android.media.MediaRoute2Info.Builder setSupportedRoutingTypes(int);
     method @NonNull public android.media.MediaRoute2Info.Builder setType(int);
     method @NonNull public android.media.MediaRoute2Info.Builder setVisibilityPublic();
     method @NonNull public android.media.MediaRoute2Info.Builder setVisibilityRestricted(@NonNull java.util.Set<java.lang.String>);
@@ -25613,6 +25636,7 @@
     method public void addOnSpatializerStateChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnSpatializerStateChangedListener);
     method public boolean canBeSpatialized(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioFormat);
     method public int getImmersiveAudioLevel();
+    method @FlaggedApi("android.media.audio.spatializer_capabilities") @NonNull public java.util.List<java.lang.Integer> getSpatializedChannelMasks();
     method public boolean isAvailable();
     method public boolean isEnabled();
     method public boolean isHeadTrackerAvailable();
@@ -33600,7 +33624,10 @@
   @FlaggedApi("android.os.cpu_gpu_headrooms") public final class CpuHeadroomParams {
     ctor public CpuHeadroomParams();
     method public int getCalculationType();
+    method @IntRange(from=0x32, to=0x2710) public long getCalculationWindowMillis();
     method public void setCalculationType(int);
+    method public void setCalculationWindowMillis(@IntRange(from=0x32, to=0x2710) int);
+    method public void setTids(@NonNull int...);
     field public static final int CPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1; // 0x1
     field public static final int CPU_HEADROOM_CALCULATION_TYPE_MIN = 0; // 0x0
   }
@@ -33855,7 +33882,9 @@
   @FlaggedApi("android.os.cpu_gpu_headrooms") public final class GpuHeadroomParams {
     ctor public GpuHeadroomParams();
     method public int getCalculationType();
+    method @IntRange(from=0x32, to=0x2710) public int getCalculationWindowMillis();
     method public void setCalculationType(int);
+    method public void setCalculationWindowMillis(@IntRange(from=0x32, to=0x2710) int);
     field public static final int GPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1; // 0x1
     field public static final int GPU_HEADROOM_CALCULATION_TYPE_MIN = 0; // 0x0
   }
@@ -37594,6 +37623,10 @@
     field public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
   }
 
+  @FlaggedApi("android.provider.new_default_account_api_enabled") public static class ContactsContract.LocalSimContactsWriteException extends java.lang.IllegalArgumentException {
+    ctor public ContactsContract.LocalSimContactsWriteException(@NonNull String);
+  }
+
   public static final class ContactsContract.PhoneLookup implements android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactsColumns android.provider.ContactsContract.PhoneLookupColumns {
     field public static final android.net.Uri CONTENT_FILTER_URI;
     field public static final android.net.Uri ENTERPRISE_CONTENT_FILTER_URI;
@@ -51925,7 +51958,7 @@
     method public int getState();
     method @FlaggedApi("com.android.server.display.feature.flags.enable_get_suggested_frame_rate") public float getSuggestedFrameRate(int);
     method public android.view.Display.Mode[] getSupportedModes();
-    method @Deprecated public float[] getSupportedRefreshRates();
+    method @FlaggedApi("com.android.server.display.feature.flags.enable_get_supported_refresh_rates") @NonNull public float[] getSupportedRefreshRates();
     method @Deprecated public int getWidth();
     method @FlaggedApi("com.android.server.display.feature.flags.enable_has_arr_support") public boolean hasArrSupport();
     method public boolean isHdr();
@@ -56483,6 +56516,7 @@
     method public float getMin();
     method public int getType();
     method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo.RangeInfo obtain(int, float, float, float);
+    field @FlaggedApi("android.view.accessibility.indeterminate_range_info") @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.RangeInfo INDETERMINATE;
     field public static final int RANGE_TYPE_FLOAT = 1; // 0x1
     field @FlaggedApi("android.view.accessibility.indeterminate_range_info") public static final int RANGE_TYPE_INDETERMINATE = 3; // 0x3
     field public static final int RANGE_TYPE_INT = 0; // 0x0
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 1a949d84..d42201d40 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -129,6 +129,7 @@
 
   public abstract class PackageManager {
     method @NonNull public String getSdkSandboxPackageName();
+    method @FlaggedApi("android.content.pm.cloud_compilation_pm") @NonNull public static android.content.pm.SigningInfo getVerifiedSigningInfo(@NonNull String, int) throws android.content.pm.SigningInfoException;
     method @RequiresPermission(android.Manifest.permission.MAKE_UID_VISIBLE) public void makeUidVisible(int, int);
     field public static final String EXTRA_VERIFICATION_ROOT_HASH = "android.content.pm.extra.VERIFICATION_ROOT_HASH";
     field public static final int MATCH_STATIC_SHARED_AND_SDK_LIBRARIES = 67108864; // 0x4000000
@@ -139,6 +140,18 @@
     method @NonNull public String getPackageName();
   }
 
+  public final class SigningInfo implements android.os.Parcelable {
+    method @FlaggedApi("android.content.pm.cloud_compilation_pm") public boolean signersMatchExactly(@NonNull android.content.pm.SigningInfo);
+    field @FlaggedApi("android.content.pm.cloud_compilation_pm") public static final int VERSION_JAR = 1; // 0x1
+    field @FlaggedApi("android.content.pm.cloud_compilation_pm") public static final int VERSION_SIGNING_BLOCK_V2 = 2; // 0x2
+    field @FlaggedApi("android.content.pm.cloud_compilation_pm") public static final int VERSION_SIGNING_BLOCK_V3 = 3; // 0x3
+    field @FlaggedApi("android.content.pm.cloud_compilation_pm") public static final int VERSION_SIGNING_BLOCK_V4 = 4; // 0x4
+  }
+
+  @FlaggedApi("android.content.pm.cloud_compilation_pm") public class SigningInfoException extends java.lang.Exception {
+    method @FlaggedApi("android.content.pm.cloud_compilation_pm") public int getCode();
+  }
+
 }
 
 package android.hardware.usb {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 9dd7d65..7bfa878 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -34,6 +34,7 @@
     field public static final String ACCESS_VIBRATOR_STATE = "android.permission.ACCESS_VIBRATOR_STATE";
     field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
     field public static final String ADD_ALWAYS_UNLOCKED_DISPLAY = "android.permission.ADD_ALWAYS_UNLOCKED_DISPLAY";
+    field @FlaggedApi("android.companion.virtualdevice.flags.enable_limited_vdm_role") public static final String ADD_MIRROR_DISPLAY = "android.permission.ADD_MIRROR_DISPLAY";
     field public static final String ADD_TRUSTED_DISPLAY = "android.permission.ADD_TRUSTED_DISPLAY";
     field public static final String ADJUST_RUNTIME_PERMISSIONS_POLICY = "android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY";
     field public static final String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
@@ -193,6 +194,7 @@
     field public static final String MANAGE_ACCESSIBILITY = "android.permission.MANAGE_ACCESSIBILITY";
     field @Deprecated public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
     field public static final String MANAGE_ACTIVITY_TASKS = "android.permission.MANAGE_ACTIVITY_TASKS";
+    field @FlaggedApi("android.security.aapm_api") public static final String MANAGE_ADVANCED_PROTECTION_MODE = "android.permission.MANAGE_ADVANCED_PROTECTION_MODE";
     field public static final String MANAGE_APP_HIBERNATION = "android.permission.MANAGE_APP_HIBERNATION";
     field public static final String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS";
     field public static final String MANAGE_APP_PREDICTIONS = "android.permission.MANAGE_APP_PREDICTIONS";
@@ -375,7 +377,6 @@
     field public static final String SERIAL_PORT = "android.permission.SERIAL_PORT";
     field @FlaggedApi("android.security.fsverity_api") public static final String SETUP_FSVERITY = "android.permission.SETUP_FSVERITY";
     field public static final String SET_ACTIVITY_WATCHER = "android.permission.SET_ACTIVITY_WATCHER";
-    field @FlaggedApi("android.security.aapm_api") public static final String SET_ADVANCED_PROTECTION_MODE = "android.permission.SET_ADVANCED_PROTECTION_MODE";
     field public static final String SET_CLIP_SOURCE = "android.permission.SET_CLIP_SOURCE";
     field public static final String SET_DEFAULT_ACCOUNT_FOR_CONTACTS = "android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS";
     field public static final String SET_HARMFUL_APP_WARNINGS = "android.permission.SET_HARMFUL_APP_WARNINGS";
@@ -3435,14 +3436,14 @@
   public class WearableSensingManager {
     method @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public int getAvailableConnectionCount();
     method @Nullable public static android.app.wearable.WearableSensingDataRequest getDataRequestFromIntent(@NonNull android.content.Intent);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideConnection(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @Deprecated @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideConnection(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideConnection(@NonNull android.app.wearable.WearableConnection, @NonNull java.util.concurrent.Executor);
     method @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideData(@NonNull android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideDataStream(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @FlaggedApi("android.app.wearable.enable_provide_read_only_pfd") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideReadOnlyParcelFileDescriptor(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void registerDataRequestObserver(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void removeAllConnections();
-    method @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public boolean removeConnection(@NonNull android.app.wearable.WearableConnection);
+    method @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void removeConnection(@NonNull android.app.wearable.WearableConnection);
     method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void startHotwordRecognition(@Nullable android.content.ComponentName, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void stopHotwordRecognition(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void unregisterDataRequestObserver(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
@@ -3542,6 +3543,7 @@
   public static interface VirtualDeviceManager.ActivityListener {
     method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public default void onActivityLaunchBlocked(int, @NonNull android.content.ComponentName, @NonNull android.os.UserHandle, @Nullable android.content.IntentSender);
     method public void onDisplayEmpty(int);
+    method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public default void onSecureWindowHidden(int);
     method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public default void onSecureWindowShown(int, @NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
     method @Deprecated public void onTopActivityChanged(int, @NonNull android.content.ComponentName);
     method public default void onTopActivityChanged(int, @NonNull android.content.ComponentName, int);
@@ -3939,6 +3941,7 @@
     field public static final String WIFI_NL80211_SERVICE = "wifinl80211";
     field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager";
     field public static final String WIFI_SCANNING_SERVICE = "wifiscanner";
+    field @FlaggedApi("android.net.wifi.flags.usd") public static final String WIFI_USD_SERVICE = "wifi_usd";
   }
 
   public final class ContextParams {
@@ -4249,6 +4252,7 @@
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setPermissionsResult(int, boolean);
     field public static final String ACTION_CONFIRM_INSTALL = "android.content.pm.action.CONFIRM_INSTALL";
     field public static final String ACTION_CONFIRM_PRE_APPROVAL = "android.content.pm.action.CONFIRM_PRE_APPROVAL";
+    field @FlaggedApi("android.content.pm.sdk_dependency_installer") public static final String ACTION_INSTALL_DEPENDENCY = "android.content.pm.action.INSTALL_DEPENDENCY";
     field public static final int DATA_LOADER_TYPE_INCREMENTAL = 2; // 0x2
     field public static final int DATA_LOADER_TYPE_NONE = 0; // 0x0
     field public static final int DATA_LOADER_TYPE_STREAMING = 1; // 0x1
@@ -5207,6 +5211,11 @@
     method @NonNull public java.util.Collection<android.hardware.contexthub.HubServiceInfo> getServiceInfoCollection();
     method @Nullable public String getTag();
     method public int getVersion();
+    field public static final int REASON_CLOSE_ENDPOINT_SESSION_REQUESTED = 4; // 0x4
+    field public static final int REASON_ENDPOINT_INVALID = 5; // 0x5
+    field public static final int REASON_ENDPOINT_STOPPED = 6; // 0x6
+    field public static final int REASON_FAILURE = 0; // 0x0
+    field public static final int REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED = 3; // 0x3
   }
 
   public static final class HubEndpoint.Builder {
@@ -5273,9 +5282,8 @@
   }
 
   @FlaggedApi("android.chre.flags.offload_api") public final class HubServiceInfo implements android.os.Parcelable {
-    ctor public HubServiceInfo(@NonNull String, int, int, int, @NonNull android.os.ParcelableHolder);
+    ctor public HubServiceInfo(@NonNull String, int, int, int);
     method public int describeContents();
-    method @NonNull public android.os.ParcelableHolder getExtendedInfo();
     method public int getFormat();
     method public int getMajorVersion();
     method public int getMinorVersion();
@@ -5290,16 +5298,17 @@
   public static final class HubServiceInfo.Builder {
     ctor public HubServiceInfo.Builder(@NonNull String, int, int, int);
     method @NonNull public android.hardware.contexthub.HubServiceInfo build();
-    method @NonNull public android.hardware.contexthub.HubServiceInfo.Builder setExtendedInfo(@Nullable android.os.Parcelable);
+  }
+
+  @FlaggedApi("android.chre.flags.offload_api") public interface IHubEndpointDiscoveryCallback {
+    method public void onEndpointsStarted(@NonNull java.util.List<android.hardware.contexthub.HubDiscoveryInfo>);
+    method public void onEndpointsStopped(@NonNull java.util.List<android.hardware.contexthub.HubDiscoveryInfo>, int);
   }
 
   @FlaggedApi("android.chre.flags.offload_api") public interface IHubEndpointLifecycleCallback {
     method public void onSessionClosed(@NonNull android.hardware.contexthub.HubEndpointSession, int);
     method @NonNull public android.hardware.contexthub.HubEndpointSessionResult onSessionOpenRequest(@NonNull android.hardware.contexthub.HubEndpointInfo, @Nullable android.hardware.contexthub.HubServiceInfo);
     method public void onSessionOpened(@NonNull android.hardware.contexthub.HubEndpointSession);
-    field public static final int REASON_CLOSE_ENDPOINT_SESSION_REQUESTED = 4; // 0x4
-    field public static final int REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED = 3; // 0x3
-    field public static final int REASON_UNSPECIFIED = 0; // 0x0
   }
 
   @FlaggedApi("android.chre.flags.offload_api") public interface IHubEndpointMessageCallback {
@@ -5447,19 +5456,13 @@
     field public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1024; // 0x400
   }
 
-  public abstract static class VirtualDisplay.Callback {
-    method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") public void onRequestedBrightnessChanged(@FloatRange(from=0.0f, to=1.0f) float);
-  }
-
   public final class VirtualDisplayConfig implements android.os.Parcelable {
-    method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @FloatRange(from=0.0f, to=1.0f) public float getDefaultBrightness();
     method @FlaggedApi("android.companion.virtualdevice.flags.virtual_display_insets") @Nullable public android.view.DisplayCutout getDisplayCutout();
     method @FlaggedApi("android.companion.virtual.flags.vdm_custom_home") public boolean isHomeSupported();
     method @FlaggedApi("com.android.window.flags.vdm_force_app_universal_resizable_api") public boolean isIgnoreActivitySizeRestrictions();
   }
 
   public static final class VirtualDisplayConfig.Builder {
-    method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setDefaultBrightness(@FloatRange(from=0.0f, to=1.0f) float);
     method @FlaggedApi("android.companion.virtualdevice.flags.virtual_display_insets") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setDisplayCutout(@Nullable android.view.DisplayCutout);
     method @FlaggedApi("android.companion.virtual.flags.vdm_custom_home") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setHomeSupported(boolean);
     method @FlaggedApi("com.android.window.flags.vdm_force_app_universal_resizable_api") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setIgnoreActivitySizeRestrictions(boolean);
@@ -6315,11 +6318,16 @@
     method @Deprecated public int registerCallback(@NonNull android.hardware.location.ContextHubManager.Callback);
     method @Deprecated public int registerCallback(android.hardware.location.ContextHubManager.Callback, android.os.Handler);
     method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpoint(@NonNull android.hardware.contexthub.HubEndpoint);
+    method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpointDiscoveryCallback(long, @NonNull android.hardware.contexthub.IHubEndpointDiscoveryCallback);
+    method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpointDiscoveryCallback(long, @NonNull android.hardware.contexthub.IHubEndpointDiscoveryCallback, @NonNull java.util.concurrent.Executor);
+    method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpointDiscoveryCallback(@NonNull String, @NonNull android.hardware.contexthub.IHubEndpointDiscoveryCallback);
+    method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpointDiscoveryCallback(@NonNull String, @NonNull android.hardware.contexthub.IHubEndpointDiscoveryCallback, @NonNull java.util.concurrent.Executor);
     method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int sendMessage(int, int, @NonNull android.hardware.location.ContextHubMessage);
     method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int unloadNanoApp(int);
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
     method @Deprecated public int unregisterCallback(@NonNull android.hardware.location.ContextHubManager.Callback);
     method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void unregisterEndpoint(@NonNull android.hardware.contexthub.HubEndpoint);
+    method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void unregisterEndpointDiscoveryCallback(@NonNull android.hardware.contexthub.IHubEndpointDiscoveryCallback);
     field public static final int AUTHORIZATION_DENIED = 0; // 0x0
     field public static final int AUTHORIZATION_DENIED_GRACE_PERIOD = 1; // 0x1
     field public static final int AUTHORIZATION_GRANTED = 2; // 0x2
@@ -7624,9 +7632,11 @@
     method public boolean isActive();
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean isMuted();
     method public boolean isSpatialized();
-    field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_APP_OPS = 8; // 0x8
+    field @Deprecated @FlaggedApi("android.media.audio.muted_by_port_volume_api") @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_APP_OPS = 8; // 0x8
     field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_CLIENT_VOLUME = 16; // 0x10
     field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_MASTER = 1; // 0x1
+    field @FlaggedApi("android.media.audio.muted_by_port_volume_api") @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_OP_CONTROL_AUDIO = 128; // 0x80
+    field @FlaggedApi("android.media.audio.muted_by_port_volume_api") @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_OP_PLAY_AUDIO = 8; // 0x8
     field @FlaggedApi("android.media.audio.muted_by_port_volume_api") @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_PORT_VOLUME = 64; // 0x40
     field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_STREAM_MUTED = 4; // 0x4
     field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_STREAM_VOLUME = 2; // 0x2
@@ -7764,7 +7774,7 @@
   }
 
   public final class MediaCas implements java.lang.AutoCloseable {
-    method @FlaggedApi("android.media.tv.flags.set_resource_holder_retain") @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public void setResourceHolderRetain(boolean);
+    method @FlaggedApi("android.media.tv.flags.set_resource_holder_retain") @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public void setResourceOwnershipRetention(boolean);
     method @FlaggedApi("android.media.tv.flags.mediacas_update_client_profile_priority") @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public boolean updateResourcePriority(int, int);
   }
 
@@ -8677,8 +8687,8 @@
     method public int setLnaEnabled(boolean);
     method public int setMaxNumberOfFrontends(int, @IntRange(from=0) int);
     method public void setOnTuneEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.frontend.OnTuneEventListener);
-    method @FlaggedApi("android.media.tv.flags.set_resource_holder_retain") @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public void setResourceHolderRetain(boolean);
     method public void setResourceLostListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.Tuner.OnResourceLostListener);
+    method @FlaggedApi("android.media.tv.flags.set_resource_holder_retain") @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public void setResourceOwnershipRetention(boolean);
     method public void shareFrontendFromTuner(@NonNull android.media.tv.tuner.Tuner);
     method public int transferOwner(@NonNull android.media.tv.tuner.Tuner);
     method public int tune(@NonNull android.media.tv.tuner.frontend.FrontendSettings);
@@ -11110,6 +11120,7 @@
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setDynamicAidGroup(@NonNull android.nfc.cardemulation.AidGroup);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setOffHostSecureElement(@NonNull String);
     method @FlaggedApi("android.nfc.nfc_observe_mode") public void setShouldDefaultToObserveMode(boolean);
+    method @FlaggedApi("android.nfc.nfc_associated_role_services") public boolean shareRolePriority();
     method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean shouldDefaultToObserveMode();
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void writeToParcel(@NonNull android.os.Parcel, int);
     field @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.ApduServiceInfo> CREATOR;
@@ -12817,8 +12828,8 @@
 
   @FlaggedApi("android.security.aapm_api") public final class AdvancedProtectionManager {
     method @NonNull public android.content.Intent createSupportIntent(@NonNull String, @Nullable String);
-    method @NonNull @RequiresPermission(android.Manifest.permission.SET_ADVANCED_PROTECTION_MODE) public java.util.List<android.security.advancedprotection.AdvancedProtectionFeature> getAdvancedProtectionFeatures();
-    method @RequiresPermission(android.Manifest.permission.SET_ADVANCED_PROTECTION_MODE) public void setAdvancedProtectionEnabled(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE) public java.util.List<android.security.advancedprotection.AdvancedProtectionFeature> getAdvancedProtectionFeatures();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE) public void setAdvancedProtectionEnabled(boolean);
     field @FlaggedApi("android.security.aapm_api") public static final String ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG = "android.security.advancedprotection.action.SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG";
     field public static final String EXTRA_SUPPORT_DIALOG_FEATURE = "android.security.advancedprotection.extra.SUPPORT_DIALOG_FEATURE";
     field public static final String EXTRA_SUPPORT_DIALOG_TYPE = "android.security.advancedprotection.extra.SUPPORT_DIALOG_TYPE";
@@ -12865,6 +12876,30 @@
 
 package android.security.intrusiondetection {
 
+  @FlaggedApi("android.security.afl_api") public final class IntrusionDetectionEvent implements android.os.Parcelable {
+    ctor public IntrusionDetectionEvent(@NonNull android.app.admin.SecurityLog.SecurityEvent);
+    ctor public IntrusionDetectionEvent(@NonNull android.app.admin.DnsEvent);
+    ctor public IntrusionDetectionEvent(@NonNull android.app.admin.ConnectEvent);
+    method @FlaggedApi("android.security.afl_api") public int describeContents();
+    method @NonNull public android.app.admin.ConnectEvent getConnectEvent();
+    method @NonNull public android.app.admin.DnsEvent getDnsEvent();
+    method @NonNull public android.app.admin.SecurityLog.SecurityEvent getSecurityEvent();
+    method @NonNull public int getType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.security.intrusiondetection.IntrusionDetectionEvent> CREATOR;
+    field public static final int NETWORK_EVENT_CONNECT = 2; // 0x2
+    field public static final int NETWORK_EVENT_DNS = 1; // 0x1
+    field public static final int SECURITY_EVENT = 0; // 0x0
+  }
+
+  @FlaggedApi("android.security.afl_api") public class IntrusionDetectionEventTransport {
+    ctor public IntrusionDetectionEventTransport();
+    method public boolean addData(@NonNull java.util.List<android.security.intrusiondetection.IntrusionDetectionEvent>);
+    method @NonNull public android.os.IBinder getBinder();
+    method public boolean initialize();
+    method public boolean release();
+  }
+
   @FlaggedApi("android.security.afl_api") public class IntrusionDetectionManager {
     method @RequiresPermission(android.Manifest.permission.READ_INTRUSION_DETECTION_STATE) public void addStateCallback(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.MANAGE_INTRUSION_DETECTION_STATE) public void disable(@NonNull java.util.concurrent.Executor, @NonNull android.security.intrusiondetection.IntrusionDetectionManager.CommandCallback);
@@ -14551,7 +14586,7 @@
     method @BinderThread public abstract void onDataStreamProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @BinderThread public abstract void onQueryServiceStatus(@NonNull java.util.Set<java.lang.Integer>, @NonNull String, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionServiceStatus>);
     method @FlaggedApi("android.app.wearable.enable_provide_read_only_pfd") @BinderThread public void onReadOnlyParcelFileDescriptorProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.PersistableBundle, @NonNull java.util.function.Consumer<java.lang.Integer>);
-    method @BinderThread public void onSecureConnectionProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @Deprecated @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @BinderThread public void onSecureConnectionProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @BinderThread public void onSecureConnectionProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.PersistableBundle, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @BinderThread public abstract void onStartDetection(@NonNull android.app.ambientcontext.AmbientContextEventRequest, @NonNull String, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionServiceStatus>, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionResult>);
     method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @BinderThread public void onStartHotwordRecognition(@NonNull java.util.function.Consumer<android.service.voice.HotwordAudioStream>, @NonNull java.util.function.Consumer<java.lang.Integer>);
@@ -16196,6 +16231,7 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getAndUpdateDefaultRespondViaMessageApplication();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallForwarding(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CallForwardingInfoCallback);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallWaitingStatus(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.carrier_id_from_carrier_identifier") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public int getCarrierIdFromCarrierIdentifier(@NonNull android.service.carrier.CarrierIdentifier);
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 1a97f7b..3a62ac9 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -541,7 +541,9 @@
     method @Nullable public android.graphics.Rect peekBitmapDimensions();
     method @Nullable public android.graphics.Rect peekBitmapDimensions(int);
     method @FlaggedApi("com.android.window.flags.multi_crop") @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setBitmapWithCrops(@Nullable android.graphics.Bitmap, @NonNull java.util.Map<android.graphics.Point,android.graphics.Rect>, boolean, int) throws java.io.IOException;
+    method @FlaggedApi("android.app.live_wallpaper_content_handling") @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setBitmapWithDescription(@Nullable android.graphics.Bitmap, @NonNull android.app.wallpaper.WallpaperDescription, boolean, int) throws java.io.IOException;
     method @FlaggedApi("com.android.window.flags.multi_crop") @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setStreamWithCrops(@NonNull java.io.InputStream, @NonNull java.util.Map<android.graphics.Point,android.graphics.Rect>, boolean, int) throws java.io.IOException;
+    method @FlaggedApi("android.app.live_wallpaper_content_handling") @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setStreamWithDescription(@NonNull java.io.InputStream, @NonNull android.app.wallpaper.WallpaperDescription, boolean, int) throws java.io.IOException;
     method public void setWallpaperZoomOut(@NonNull android.os.IBinder, float);
     method public boolean shouldEnableWideColorGamut();
     method public boolean wallpaperSupportsWcg(int);
@@ -907,6 +909,15 @@
 
 }
 
+package android.app.wallpaper {
+
+  public static final class WallpaperDescription.Builder {
+    method @NonNull public android.app.wallpaper.WallpaperDescription.Builder setCropHints(@NonNull java.util.Map<android.graphics.Point,android.graphics.Rect>);
+    method @NonNull public android.app.wallpaper.WallpaperDescription.Builder setCropHints(@NonNull android.util.SparseArray<android.graphics.Rect>);
+  }
+
+}
+
 package android.appwidget {
 
   public class AppWidgetManager {
@@ -3730,6 +3741,7 @@
     method @NonNull public android.view.Display.Mode getDefaultMode();
     method public int getRemoveMode();
     method @NonNull public int[] getReportedHdrTypes();
+    method @NonNull public float[] getSupportedRefreshRatesLegacy();
     method @NonNull public android.graphics.ColorSpace[] getSupportedWideColorGamut();
     method @Nullable public android.view.Display.Mode getSystemPreferredDisplayMode();
     method public int getType();
@@ -3752,6 +3764,7 @@
 
   public static final class Display.Mode implements android.os.Parcelable {
     ctor public Display.Mode(int, int, float);
+    method public float getVsyncRate();
     method public boolean isSynthetic();
     method public boolean matches(int, int, float);
   }
diff --git a/core/java/Android.bp b/core/java/Android.bp
index bdd7a37..ce767f4 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -690,43 +690,8 @@
 
 // protolog end
 
-// Whether to enable read-only system feature codegen.
-gen_readonly_feature_apis = select(release_flag("RELEASE_USE_SYSTEM_FEATURE_BUILD_FLAGS"), {
-    true: "true",
-    false: "false",
-    default: "false",
-})
-
-// Generates com.android.internal.pm.RoSystemFeatures, optionally compiling in
-// details about fixed system features defined by build flags. When disabled,
-// the APIs are simply passthrough stubs with no meaningful side effects.
-// TODO(b/203143243): Implement the `--feature=` aggregation  directly with a native soong module.
-genrule {
+java_system_features_srcs {
     name: "systemfeatures-gen-srcs",
-    cmd: "$(location systemfeatures-gen-tool) com.android.internal.pm.RoSystemFeatures " +
-        // --readonly=false (default) makes the codegen an effective no-op passthrough API.
-        " --readonly=" + gen_readonly_feature_apis +
-        " --feature=AUTOMOTIVE:" + select(release_flag("RELEASE_SYSTEM_FEATURE_AUTOMOTIVE"), {
-            any @ value: value,
-            default: "",
-        }) + " --feature=EMBEDDED:" + select(release_flag("RELEASE_SYSTEM_FEATURE_EMBEDDED"), {
-            any @ value: value,
-            default: "",
-        }) + " --feature=LEANBACK:" + select(release_flag("RELEASE_SYSTEM_FEATURE_LEANBACK"), {
-            any @ value: value,
-            default: "",
-        }) + " --feature=PC:" + select(release_flag("RELEASE_SYSTEM_FEATURE_PC"), {
-            any @ value: value,
-            default: "",
-        }) + " --feature=TELEVISION:" + select(release_flag("RELEASE_SYSTEM_FEATURE_TELEVISION"), {
-            any @ value: value,
-            default: "",
-        }) + " --feature=WATCH:" + select(release_flag("RELEASE_SYSTEM_FEATURE_WATCH"), {
-            any @ value: value,
-            default: "",
-        }) + " > $(out)",
-    out: [
-        "RoSystemFeatures.java",
-    ],
-    tools: ["systemfeatures-gen-tool"],
+    full_class_name: "com.android.internal.pm.RoSystemFeatures",
+    visibility: ["//visibility:private"],
 }
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index d1eb8e8..4bf87f91 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -141,6 +141,14 @@
     }
 
     /**
+     * @see #sPostNotifyEndListenerEnabled
+     * @hide
+     */
+    public static boolean isPostNotifyEndListenerEnabled() {
+        return sPostNotifyEndListenerEnabled;
+    }
+
+    /**
      * Starts this animation. If the animation has a nonzero startDelay, the animation will start
      * running after that delay elapses. A non-delayed animation will have its initial
      * value(s) set immediately, followed by calls to
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index d9f8d33..eccb6ff 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -1164,6 +1164,19 @@
             @UserIdInt int userId, int notificationId);
 
     /**
+     * Notifies that a media service associated with a media session has transitioned to a
+     * "user-engaged" state. Upon receiving this notification, service will transition to the
+     * foreground state. It should only be called by
+     * {@link com.android.server.media.MediaSessionService}
+     *
+     * @param packageName The package name of the app running the media service.
+     * @param userId The user ID associated with the service.
+     * @param notificationId The ID of the media notification associated with the service.
+     */
+    public abstract void notifyActiveMediaForegroundService(@NonNull String packageName,
+            @UserIdInt int userId, int notificationId);
+
+    /**
      * Same as {@link android.app.IActivityManager#startProfile(int userId)}, but it would succeed
      * even if the profile is disabled - it should only be called by
      * {@link com.android.server.devicepolicy.DevicePolicyManagerService} when starting a profile
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index cb7b115..f8186d6 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -8843,10 +8843,10 @@
         // Call per-process mainline module initialization.
         initializeMainlineModules();
 
-        Process.setArgV0("<pre-initialized>");
-
         Looper.prepareMainLooper();
 
+        Process.setArgV0("<pre-initialized>");
+
         // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
         // It will be in the format "seq=114"
         long startSeq = 0;
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 7e0a9b6..3cbea87 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -130,7 +130,6 @@
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.Immutable;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.pm.RoSystemFeatures;
@@ -1020,6 +1019,33 @@
         }
     }
 
+    @Override
+    public void setPageSizeAppCompatFlagsSettingsOverride(String packageName, boolean enabled) {
+        try {
+            mPM.setPageSizeAppCompatFlagsSettingsOverride(packageName, enabled);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
+    public boolean isPageSizeCompatEnabled(String packageName) {
+        try {
+            return mPM.isPageSizeCompatEnabled(packageName);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
+    public String getPageSizeCompatWarningMessage(String packageName) {
+        try {
+            return mPM.getPageSizeCompatWarningMessage(packageName);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     private static List<byte[]> encodeCertificates(List<Certificate> certs) throws
             CertificateEncodingException {
         if (certs == null) {
diff --git a/core/java/android/app/BroadcastStickyCache.java b/core/java/android/app/BroadcastStickyCache.java
new file mode 100644
index 0000000..fe2e107
--- /dev/null
+++ b/core/java/android/app/BroadcastStickyCache.java
@@ -0,0 +1,215 @@
+/*
+ * 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.app;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.Context.RegisterReceiverFlags;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbManager;
+import android.media.AudioManager;
+import android.net.ConnectivityManager;
+import android.net.TetheringManager;
+import android.net.nsd.NsdManager;
+import android.net.wifi.WifiManager;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.os.IpcDataCache;
+import android.os.IpcDataCache.Config;
+import android.os.UpdateLock;
+import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
+import android.view.WindowManagerPolicyConstants;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+
+/** @hide */
+public class BroadcastStickyCache {
+
+    @VisibleForTesting
+    public static final String[] STICKY_BROADCAST_ACTIONS = {
+            AudioManager.ACTION_HDMI_AUDIO_PLUG,
+            AudioManager.ACTION_HEADSET_PLUG,
+            AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED,
+            AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED,
+            AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION,
+            AudioManager.RINGER_MODE_CHANGED_ACTION,
+            ConnectivityManager.CONNECTIVITY_ACTION,
+            Intent.ACTION_BATTERY_CHANGED,
+            Intent.ACTION_DEVICE_STORAGE_FULL,
+            Intent.ACTION_DEVICE_STORAGE_LOW,
+            Intent.ACTION_SIM_STATE_CHANGED,
+            NsdManager.ACTION_NSD_STATE_CHANGED,
+            TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED,
+            TetheringManager.ACTION_TETHER_STATE_CHANGED,
+            UpdateLock.UPDATE_LOCK_CHANGED,
+            UsbManager.ACTION_USB_STATE,
+            WifiManager.ACTION_WIFI_SCAN_AVAILABILITY_CHANGED,
+            WifiManager.NETWORK_STATE_CHANGED_ACTION,
+            WifiManager.SUPPLICANT_STATE_CHANGED_ACTION,
+            WifiManager.WIFI_STATE_CHANGED_ACTION,
+            WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION,
+            WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED,
+            "android.net.conn.INET_CONDITION_ACTION" // ConnectivityManager.INET_CONDITION_ACTION
+    };
+
+    @VisibleForTesting
+    public static final ArrayMap<String, String> sActionApiNameMap = new ArrayMap<>();
+
+    private static final ArrayMap<String, IpcDataCache.Config> sActionConfigMap = new ArrayMap<>();
+
+    private static final ArrayMap<StickyBroadcastFilter, IpcDataCache<Void, Intent>>
+            sFilterCacheMap = new ArrayMap<>();
+
+    static {
+        sActionApiNameMap.put(AudioManager.ACTION_HDMI_AUDIO_PLUG, "hdmi_audio_plug");
+        sActionApiNameMap.put(AudioManager.ACTION_HEADSET_PLUG, "headset_plug");
+        sActionApiNameMap.put(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED,
+                "sco_audio_state_changed");
+        sActionApiNameMap.put(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED,
+                "action_sco_audio_state_updated");
+        sActionApiNameMap.put(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION,
+                "internal_ringer_mode_changed_action");
+        sActionApiNameMap.put(AudioManager.RINGER_MODE_CHANGED_ACTION,
+                "ringer_mode_changed");
+        sActionApiNameMap.put(ConnectivityManager.CONNECTIVITY_ACTION,
+                "connectivity_change");
+        sActionApiNameMap.put(Intent.ACTION_BATTERY_CHANGED, "battery_changed");
+        sActionApiNameMap.put(Intent.ACTION_DEVICE_STORAGE_FULL, "device_storage_full");
+        sActionApiNameMap.put(Intent.ACTION_DEVICE_STORAGE_LOW, "device_storage_low");
+        sActionApiNameMap.put(Intent.ACTION_SIM_STATE_CHANGED, "sim_state_changed");
+        sActionApiNameMap.put(NsdManager.ACTION_NSD_STATE_CHANGED, "nsd_state_changed");
+        sActionApiNameMap.put(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED,
+                "service_providers_updated");
+        sActionApiNameMap.put(TetheringManager.ACTION_TETHER_STATE_CHANGED,
+                "tether_state_changed");
+        sActionApiNameMap.put(UpdateLock.UPDATE_LOCK_CHANGED, "update_lock_changed");
+        sActionApiNameMap.put(UsbManager.ACTION_USB_STATE, "usb_state");
+        sActionApiNameMap.put(WifiManager.ACTION_WIFI_SCAN_AVAILABILITY_CHANGED,
+                "wifi_scan_availability_changed");
+        sActionApiNameMap.put(WifiManager.NETWORK_STATE_CHANGED_ACTION,
+                "network_state_change");
+        sActionApiNameMap.put(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION,
+                "supplicant_state_change");
+        sActionApiNameMap.put(WifiManager.WIFI_STATE_CHANGED_ACTION, "wifi_state_changed");
+        sActionApiNameMap.put(
+                WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION, "wifi_p2p_state_changed");
+        sActionApiNameMap.put(
+                WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED, "hdmi_plugged");
+        sActionApiNameMap.put(
+                "android.net.conn.INET_CONDITION_ACTION", "inet_condition_action");
+    }
+
+    /**
+     * Checks whether we can use caching for the given filter.
+     */
+    public static boolean useCache(@Nullable IntentFilter filter) {
+        return Flags.useStickyBcastCache()
+                && filter != null
+                && filter.safeCountActions() == 1
+                && ArrayUtils.contains(STICKY_BROADCAST_ACTIONS, filter.getAction(0));
+    }
+
+    public static void invalidateCache(@NonNull String action) {
+        if (!Flags.useStickyBcastCache()
+                || !ArrayUtils.contains(STICKY_BROADCAST_ACTIONS, action)) {
+            return;
+        }
+        IpcDataCache.invalidateCache(IpcDataCache.MODULE_SYSTEM,
+                sActionApiNameMap.get(action));
+    }
+
+    public static void invalidateAllCaches() {
+        for (int i = sActionApiNameMap.size() - 1; i >= 0; i--) {
+            IpcDataCache.invalidateCache(IpcDataCache.MODULE_SYSTEM,
+                    sActionApiNameMap.valueAt(i));
+        }
+    }
+
+    /**
+     * Returns the cached {@link Intent} based on the filter, if exits otherwise
+     * fetches the value from the service.
+     */
+    @Nullable
+    public static Intent getIntent(
+            @NonNull IApplicationThread applicationThread,
+            @NonNull String mBasePackageName,
+            @Nullable String attributionTag,
+            @NonNull IntentFilter filter,
+            @Nullable String broadcastPermission,
+            @UserIdInt int userId,
+            @RegisterReceiverFlags int flags) {
+        IpcDataCache<Void, Intent> intentDataCache = findIpcDataCache(filter);
+
+        if (intentDataCache == null) {
+            final String action = filter.getAction(0);
+            final StickyBroadcastFilter stickyBroadcastFilter =
+                    new StickyBroadcastFilter(filter, action);
+            final Config config = getConfig(action);
+
+            intentDataCache =
+                    new IpcDataCache<>(config,
+                            (query) -> ActivityManager.getService().registerReceiverWithFeature(
+                                    applicationThread,
+                                    mBasePackageName,
+                                    attributionTag,
+                                    /* receiverId= */ "null",
+                                    /* receiver= */ null,
+                                    filter,
+                                    broadcastPermission,
+                                    userId,
+                                    flags));
+            sFilterCacheMap.put(stickyBroadcastFilter, intentDataCache);
+        }
+        return intentDataCache.query(null);
+    }
+
+    @VisibleForTesting
+    public static void clearCacheForTest() {
+        sFilterCacheMap.clear();
+    }
+
+    @Nullable
+    private static IpcDataCache<Void, Intent> findIpcDataCache(
+            @NonNull IntentFilter filter) {
+        for (int i = sFilterCacheMap.size() - 1; i >= 0; i--) {
+            StickyBroadcastFilter existingFilter = sFilterCacheMap.keyAt(i);
+            if (filter.getAction(0).equals(existingFilter.action())
+                    && IntentFilter.filterEquals(existingFilter.filter(), filter)) {
+                return sFilterCacheMap.valueAt(i);
+            }
+        }
+        return null;
+    }
+
+    @NonNull
+    private static IpcDataCache.Config getConfig(@NonNull String action) {
+        if (!sActionConfigMap.containsKey(action)) {
+            // We only need 1 entry per cache but just to be on the safer side we are choosing 32
+            // although we don't expect more than 1.
+            sActionConfigMap.put(action,
+                    new Config(32, IpcDataCache.MODULE_SYSTEM, sActionApiNameMap.get(action)));
+        }
+
+        return sActionConfigMap.get(action);
+    }
+
+    @VisibleForTesting
+    private record StickyBroadcastFilter(@NonNull IntentFilter filter, @NonNull String action) {
+    }
+}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index cd56957..dcbdc23 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1922,10 +1922,23 @@
             }
         }
         try {
-            final Intent intent = ActivityManager.getService().registerReceiverWithFeature(
-                    mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(),
-                    AppOpsManager.toReceiverId(receiver), rd, filter, broadcastPermission, userId,
-                    flags);
+            final Intent intent;
+            if (receiver == null && BroadcastStickyCache.useCache(filter)) {
+                intent = BroadcastStickyCache.getIntent(
+                        mMainThread.getApplicationThread(),
+                        mBasePackageName,
+                        getAttributionTag(),
+                        filter,
+                        broadcastPermission,
+                        userId,
+                        flags);
+            } else {
+                intent = ActivityManager.getService().registerReceiverWithFeature(
+                        mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(),
+                        AppOpsManager.toReceiverId(receiver), rd, filter, broadcastPermission,
+                        userId, flags);
+            }
+
             if (intent != null) {
                 intent.setExtrasClassLoader(getClassLoader());
                 // TODO: determine at registration time if caller is
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 0668958..5048661 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -1028,4 +1028,14 @@
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.DEVICE_POWER)")
     void noteAppRestrictionEnabled(in String packageName, int uid, int restrictionType,
             boolean enabled, int reason, in String subReason, int source, long threshold);
+
+    /**
+     * Creates and returns a new IntentCreatorToken that keeps the creatorUid and refreshes key
+     * fields of the intent passed in.
+     *
+     * @param intent The intent with key fields out of sync of the IntentCreatorToken it contains.
+     * @hide
+     */
+    @EnforcePermission("INTERACT_ACROSS_USERS_FULL")
+    IBinder refreshIntentCreatorToken(in Intent intent);
 }
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 9bb16ae..a6c1a57 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -270,4 +270,6 @@
 
     int[] getAllowedAdjustmentKeyTypes();
     void setAssistantAdjustmentKeyTypeState(int type, boolean enabled);
+    String[] getTypeAdjustmentDeniedPackages();
+    void setTypeAdjustmentForPackageState(String pkg, boolean enabled);
 }
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index f2228f9..4a9a286 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -178,6 +178,11 @@
     void onRecentTaskListFrozenChanged(boolean frozen);
 
     /**
+     *  Called when a task is removed from the recent tasks list as a result of adding a new task.
+     */
+    void onRecentTaskRemovedForAddTask(int taskId);
+
+    /**
      * Called when a task gets or loses focus.
      *
      * @param taskId id of the task.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index b84c91b..0268b5b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -441,8 +441,8 @@
 
     /**
      * A large-format version of {@link #contentView}, giving the Notification an
-     * opportunity to show more detail. The system UI may choose to show this
-     * instead of the normal content view at its discretion.
+     * opportunity to show more detail when expanded. The system UI may choose
+     * to show this instead of the normal content view at its discretion.
      *
      * As of N, this field may be null. The expanded notification view is determined by the
      * inputs to {@link Notification.Builder}; a custom RemoteViews can optionally be
@@ -814,21 +814,21 @@
         if (Flags.notificationsRedesignTemplates()) {
             return switch (layoutId) {
                 case R.layout.notification_2025_template_collapsed_base,
+                     R.layout.notification_2025_template_expanded_base,
                      R.layout.notification_2025_template_heads_up_base,
                      R.layout.notification_2025_template_header,
-                     R.layout.notification_template_material_big_base,
-                     R.layout.notification_template_material_big_picture,
-                     R.layout.notification_template_material_big_text,
-                     R.layout.notification_template_material_inbox,
-                     R.layout.notification_template_material_messaging,
-                     R.layout.notification_template_material_big_messaging,
-                     R.layout.notification_template_material_conversation,
-                     R.layout.notification_template_material_media,
-                     R.layout.notification_template_material_big_media,
-                     R.layout.notification_template_material_call,
-                     R.layout.notification_template_material_big_call,
-                     R.layout.notification_template_header -> true;
-                case R.layout.notification_template_material_progress -> Flags.apiRichOngoing();
+                     R.layout.notification_2025_template_conversation,
+                     R.layout.notification_2025_template_collapsed_call,
+                     R.layout.notification_2025_template_expanded_call,
+                     R.layout.notification_2025_template_collapsed_messaging,
+                     R.layout.notification_2025_template_expanded_messaging,
+                     R.layout.notification_2025_template_collapsed_media,
+                     R.layout.notification_2025_template_expanded_media,
+                     R.layout.notification_2025_template_expanded_big_picture,
+                     R.layout.notification_2025_template_expanded_big_text,
+                     R.layout.notification_2025_template_expanded_inbox -> true;
+                case R.layout.notification_2025_template_expanded_progress
+                        -> Flags.apiRichOngoing();
                 default -> false;
             };
         }
@@ -1337,7 +1337,7 @@
     public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
 
     /**
-     * {@link #extras} key: this is the longer text shown in the big form of a
+     * {@link #extras} key: this is the longer text shown in the expanded form of a
      * {@link BigTextStyle} notification, as supplied to
      * {@link BigTextStyle#bigText(CharSequence)}.
      */
@@ -3263,6 +3263,7 @@
     public boolean hasPromotableCharacteristics() {
         return isColorizedRequested()
                 && hasTitle()
+                && !isGroupSummary()
                 && !containsCustomViews()
                 && hasPromotableStyle();
     }
@@ -5918,12 +5919,12 @@
 
         private RemoteViews applyStandardTemplate(int resId, StandardTemplateParams p,
                 TemplateBindResult result) {
-            p.headerless(resId == getBaseLayoutResource()
+            p.headerless(resId == getCollapsedBaseLayoutResource()
                     || resId == getHeadsUpBaseLayoutResource()
                     || resId == getCompactHeadsUpBaseLayoutResource()
                     || resId == getMessagingCompactHeadsUpLayoutResource()
-                    || resId == getMessagingLayoutResource()
-                    || resId == R.layout.notification_template_material_media);
+                    || resId == getCollapsedMessagingLayoutResource()
+                    || resId == getCollapsedMediaLayoutResource());
             RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId);
 
             resetStandardTemplate(contentView);
@@ -5963,7 +5964,7 @@
 
         private static void setHeaderlessVerticalMargins(RemoteViews contentView,
                 StandardTemplateParams p, boolean hasSecondLine) {
-            if (!p.mHeaderless) {
+            if (Flags.notificationsRedesignTemplates() || !p.mHeaderless) {
                 return;
             }
             int marginDimen = hasSecondLine
@@ -6377,7 +6378,7 @@
             boolean hideSnoozeButton = mN.isFgsOrUij()
                     || mN.fullScreenIntent != null
                     || isBackgroundColorized(p)
-                    || p.mViewType != StandardTemplateParams.VIEW_TYPE_BIG;
+                    || p.mViewType != StandardTemplateParams.VIEW_TYPE_EXPANDED;
             big.setBoolean(R.id.snooze_button, "setEnabled", !hideSnoozeButton);
             if (hideSnoozeButton) {
                 // Only hide; NotificationContentView will show it when it adds the click listener
@@ -6444,10 +6445,13 @@
                 // Clear view padding to allow buttons to start on the left edge.
                 // This must be done before 'setEmphasizedMode' which sets top/bottom margins.
                 big.setViewPadding(R.id.actions, 0, 0, 0, 0);
-                // Add an optional indent that will make buttons start at the correct column when
-                // there is enough space to do so (and fall back to the left edge if not).
-                big.setInt(R.id.actions, "setCollapsibleIndentDimen",
-                        R.dimen.call_notification_collapsible_indent);
+                if (!Flags.notificationsRedesignTemplates()) {
+                    // Add an optional indent that will make buttons start at the correct column
+                    // when there is enough space to do so (and fall back to the left edge if not).
+                    // This is handled directly in NotificationActionListLayout in the new design.
+                    big.setInt(R.id.actions, "setCollapsibleIndentDimen",
+                            R.dimen.call_notification_collapsible_indent);
+                }
                 if (evenlyDividedCallStyleActionLayout()) {
                     if (CallStyle.DEBUG_NEW_ACTION_LAYOUT) {
                         Log.d(TAG, "setting evenly divided mode on action list");
@@ -6582,19 +6586,21 @@
                     .decorationType(StandardTemplateParams.DECORATION_MINIMAL)
                     .fillTextsFrom(this);
             TemplateBindResult result = new TemplateBindResult();
-            RemoteViews standard = applyStandardTemplate(getBaseLayoutResource(), p, result);
+            RemoteViews standard = applyStandardTemplate(getCollapsedBaseLayoutResource(),
+                    p, result);
             buildCustomContentIntoTemplate(mContext, standard, customContent,
                     p, result);
             return standard;
         }
 
-        private RemoteViews minimallyDecoratedBigContentView(@NonNull RemoteViews customContent) {
+        private RemoteViews minimallyDecoratedExpandedContentView(
+                @NonNull RemoteViews customContent) {
             StandardTemplateParams p = mParams.reset()
-                    .viewType(StandardTemplateParams.VIEW_TYPE_BIG)
+                    .viewType(StandardTemplateParams.VIEW_TYPE_EXPANDED)
                     .decorationType(StandardTemplateParams.DECORATION_MINIMAL)
                     .fillTextsFrom(this);
             TemplateBindResult result = new TemplateBindResult();
-            RemoteViews standard = applyStandardTemplateWithActions(getBigBaseLayoutResource(),
+            RemoteViews standard = applyStandardTemplateWithActions(getExpandedBaseLayoutResource(),
                     p, result);
             buildCustomContentIntoTemplate(mContext, standard, customContent,
                     p, result);
@@ -6640,7 +6646,7 @@
             StandardTemplateParams p = mParams.reset()
                     .viewType(StandardTemplateParams.VIEW_TYPE_NORMAL)
                     .fillTextsFrom(this);
-            return applyStandardTemplate(getBaseLayoutResource(), p, null /* result */);
+            return applyStandardTemplate(getCollapsedBaseLayoutResource(), p, null /* result */);
         }
 
         private boolean useExistingRemoteView(RemoteViews customContent) {
@@ -6678,24 +6684,29 @@
          */
         @Deprecated
         public RemoteViews createBigContentView() {
+            return createExpandedContentView();
+        }
+
+        private RemoteViews createExpandedContentView() {
             RemoteViews result = null;
             if (useExistingRemoteView(mN.bigContentView)) {
                 return fullyCustomViewRequiresDecoration(false /* fromStyle */)
-                        ? minimallyDecoratedBigContentView(mN.bigContentView) : mN.bigContentView;
+                        ? minimallyDecoratedExpandedContentView(mN.bigContentView)
+                        : mN.bigContentView;
             }
             if (mStyle != null) {
-                result = mStyle.makeBigContentView();
+                result = mStyle.makeExpandedContentView();
                 if (fullyCustomViewRequiresDecoration(true /* fromStyle */)) {
-                    result = minimallyDecoratedBigContentView(result);
+                    result = minimallyDecoratedExpandedContentView(result);
                 }
             }
             if (result == null) {
-                if (bigContentViewRequired()) {
+                if (expandedContentViewRequired()) {
                     StandardTemplateParams p = mParams.reset()
-                            .viewType(StandardTemplateParams.VIEW_TYPE_BIG)
+                            .viewType(StandardTemplateParams.VIEW_TYPE_EXPANDED)
                             .allowTextWithProgress(true)
                             .fillTextsFrom(this);
-                    result = applyStandardTemplateWithActions(getBigBaseLayoutResource(), p,
+                    result = applyStandardTemplateWithActions(getExpandedBaseLayoutResource(), p,
                             null /* result */);
                 }
             }
@@ -6709,7 +6720,7 @@
         // apps can detect the change, it's most likely that the changes will simply result in
         // visual regressions.
         @SuppressWarnings("AndroidFrameworkCompatChange")
-        private boolean bigContentViewRequired() {
+        private boolean expandedContentViewRequired() {
             if (Flags.notificationExpansionOptional()) {
                 // Notifications without a bigContentView, style, or actions do not need to expand
                 boolean exempt = mN.bigContentView == null
@@ -7520,7 +7531,7 @@
         }
 
         @UnsupportedAppUsage
-        private int getBaseLayoutResource() {
+        private int getCollapsedBaseLayoutResource() {
             if (Flags.notificationsRedesignTemplates()) {
                 return R.layout.notification_2025_template_collapsed_base;
             } else {
@@ -7544,36 +7555,100 @@
             return R.layout.notification_template_material_messaging_compact_heads_up;
         }
 
-        private int getBigBaseLayoutResource() {
-            return R.layout.notification_template_material_big_base;
+        private int getExpandedBaseLayoutResource() {
+            if (Flags.notificationsRedesignTemplates()) {
+                return R.layout.notification_2025_template_expanded_base;
+            } else {
+                return R.layout.notification_template_material_big_base;
+            }
         }
 
         private int getBigPictureLayoutResource() {
-            return R.layout.notification_template_material_big_picture;
+            if (Flags.notificationsRedesignTemplates()) {
+                return R.layout.notification_2025_template_expanded_big_picture;
+            } else {
+                return R.layout.notification_template_material_big_picture;
+            }
         }
 
         private int getBigTextLayoutResource() {
-            return R.layout.notification_template_material_big_text;
+            if (Flags.notificationsRedesignTemplates()) {
+                return R.layout.notification_2025_template_expanded_big_text;
+            } else {
+                return R.layout.notification_template_material_big_text;
+            }
         }
 
         private int getInboxLayoutResource() {
-            return R.layout.notification_template_material_inbox;
+            if (Flags.notificationsRedesignTemplates()) {
+                return R.layout.notification_2025_template_expanded_inbox;
+            } else {
+                return R.layout.notification_template_material_inbox;
+            }
         }
 
-        private int getMessagingLayoutResource() {
-            return R.layout.notification_template_material_messaging;
+        private int getCollapsedMessagingLayoutResource() {
+            if (Flags.notificationsRedesignTemplates()) {
+                return R.layout.notification_2025_template_collapsed_messaging;
+            } else {
+                return R.layout.notification_template_material_messaging;
+            }
         }
 
-        private int getBigMessagingLayoutResource() {
-            return R.layout.notification_template_material_big_messaging;
+        private int getExpandedMessagingLayoutResource() {
+            if (Flags.notificationsRedesignTemplates()) {
+                return R.layout.notification_2025_template_expanded_messaging;
+            } else {
+                return R.layout.notification_template_material_big_messaging;
+            }
+        }
+
+        private int getCollapsedMediaLayoutResource() {
+            if (Flags.notificationsRedesignTemplates()) {
+                return R.layout.notification_2025_template_collapsed_media;
+            } else {
+                return R.layout.notification_template_material_media;
+            }
+        }
+
+        private int getExpandedMediaLayoutResource() {
+            if (Flags.notificationsRedesignTemplates()) {
+                return R.layout.notification_2025_template_expanded_media;
+            } else {
+                return R.layout.notification_template_material_big_media;
+            }
         }
 
         private int getConversationLayoutResource() {
-            return R.layout.notification_template_material_conversation;
+            if (Flags.notificationsRedesignTemplates()) {
+                return R.layout.notification_2025_template_conversation;
+            } else {
+                return R.layout.notification_template_material_conversation;
+            }
+        }
+
+        private int getCollapsedCallLayoutResource() {
+            if (Flags.notificationsRedesignTemplates()) {
+                return R.layout.notification_2025_template_collapsed_call;
+            } else {
+                return R.layout.notification_template_material_call;
+            }
+        }
+
+        private int getExpandedCallLayoutResource() {
+            if (Flags.notificationsRedesignTemplates()) {
+                return R.layout.notification_2025_template_expanded_call;
+            } else {
+                return R.layout.notification_template_material_big_call;
+            }
         }
 
         private int getProgressLayoutResource() {
-            return R.layout.notification_template_material_progress;
+            if (Flags.notificationsRedesignTemplates()) {
+                return R.layout.notification_2025_template_expanded_progress;
+            } else {
+                return R.layout.notification_template_material_progress;
+            }
         }
 
         private int getActionLayoutResource() {
@@ -8033,7 +8108,7 @@
         protected Builder mBuilder;
 
         /**
-         * Overrides ContentTitle in the big form of the template.
+         * Overrides ContentTitle in the expanded form of the template.
          * This defaults to the value passed to setContentTitle().
          */
         protected void internalSetBigContentTitle(CharSequence title) {
@@ -8041,7 +8116,7 @@
         }
 
         /**
-         * Set the first line of text after the detail section in the big form of the template.
+         * Set the first line of text after the detail section in the expanded form of the template.
          */
         protected void internalSetSummaryText(CharSequence cs) {
             mSummaryText = cs;
@@ -8104,10 +8179,10 @@
         }
 
         /**
-         * Construct a Style-specific RemoteViews for the final big notification layout.
+         * Construct a Style-specific RemoteViews for the final expanded notification layout.
          * @hide
          */
-        public RemoteViews makeBigContentView() {
+        public RemoteViews makeExpandedContentView() {
             return null;
         }
 
@@ -8271,7 +8346,7 @@
         }
 
         /**
-         * Overrides ContentTitle in the big form of the template.
+         * Overrides ContentTitle in the expanded form of the template.
          * This defaults to the value passed to setContentTitle().
          */
         @NonNull
@@ -8281,7 +8356,7 @@
         }
 
         /**
-         * Set the first line of text after the detail section in the big form of the template.
+         * Set the first line of text after the detail section in the expanded form of the template.
          */
         @NonNull
         public BigPictureStyle setSummaryText(@Nullable CharSequence cs) {
@@ -8340,7 +8415,7 @@
         }
 
         /**
-         * Override the large icon when the big notification is shown.
+         * Override the large icon when the expanded notification is shown.
          */
         @NonNull
         public BigPictureStyle bigLargeIcon(@Nullable Bitmap b) {
@@ -8348,7 +8423,7 @@
         }
 
         /**
-         * Override the large icon when the big notification is shown.
+         * Override the large icon when the expanded notification is shown.
          */
         @NonNull
         public BigPictureStyle bigLargeIcon(@Nullable Icon icon) {
@@ -8412,7 +8487,7 @@
                     .viewType(StandardTemplateParams.VIEW_TYPE_NORMAL)
                     .fillTextsFrom(mBuilder)
                     .promotedPicture(mPictureIcon);
-            return getStandardView(mBuilder.getBaseLayoutResource(), p, null /* result */);
+            return getStandardView(mBuilder.getCollapsedBaseLayoutResource(), p, null /* result */);
         }
 
         /**
@@ -8434,7 +8509,7 @@
         /**
          * @hide
          */
-        public RemoteViews makeBigContentView() {
+        public RemoteViews makeExpandedContentView() {
             // Replace mN.mLargeIcon with mBigLargeIcon if mBigLargeIconSet
             // This covers the following cases:
             //   1. mBigLargeIconSet -> mBigLargeIcon (null or non-null) applies, overrides
@@ -8453,7 +8528,7 @@
             }
 
             StandardTemplateParams p = mBuilder.mParams.reset()
-                    .viewType(StandardTemplateParams.VIEW_TYPE_BIG).fillTextsFrom(mBuilder);
+                    .viewType(StandardTemplateParams.VIEW_TYPE_EXPANDED).fillTextsFrom(mBuilder);
             RemoteViews contentView = getStandardView(mBuilder.getBigPictureLayoutResource(),
                     p, null /* result */);
             if (mSummaryTextSet) {
@@ -8600,7 +8675,7 @@
         }
 
         /**
-         * Overrides ContentTitle in the big form of the template.
+         * Overrides ContentTitle in the expanded form of the template.
          * This defaults to the value passed to setContentTitle().
          */
         public BigTextStyle setBigContentTitle(CharSequence title) {
@@ -8609,7 +8684,7 @@
         }
 
         /**
-         * Set the first line of text after the detail section in the big form of the template.
+         * Set the first line of text after the detail section in the expanded form of the template.
          */
         public BigTextStyle setSummaryText(CharSequence cs) {
             internalSetSummaryText(safeCharSequence(cs));
@@ -8617,7 +8692,7 @@
         }
 
         /**
-         * Provide the longer text to be displayed in the big form of the
+         * Provide the longer text to be displayed in the expanded form of the
          * template in place of the content text.
          */
         public BigTextStyle bigText(CharSequence cs) {
@@ -8661,7 +8736,7 @@
             if (increasedHeight) {
                 ArrayList<Action> originalActions = mBuilder.mActions;
                 mBuilder.mActions = new ArrayList<>();
-                RemoteViews remoteViews = makeBigContentView();
+                RemoteViews remoteViews = makeExpandedContentView();
                 mBuilder.mActions = originalActions;
                 return remoteViews;
             }
@@ -8675,7 +8750,7 @@
         public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
             if (increasedHeight && mBuilder.mActions.size() > 0) {
                 // TODO(b/163626038): pass VIEW_TYPE_HEADS_UP?
-                return makeBigContentView();
+                return makeExpandedContentView();
             }
             return super.makeHeadsUpContentView(increasedHeight);
         }
@@ -8683,9 +8758,9 @@
         /**
          * @hide
          */
-        public RemoteViews makeBigContentView() {
+        public RemoteViews makeExpandedContentView() {
             StandardTemplateParams p = mBuilder.mParams.reset()
-                    .viewType(StandardTemplateParams.VIEW_TYPE_BIG)
+                    .viewType(StandardTemplateParams.VIEW_TYPE_EXPANDED)
                     .allowTextWithProgress(true)
                     .textViewId(R.id.big_text)
                     .fillTextsFrom(mBuilder);
@@ -9357,20 +9432,20 @@
          * @hide
          */
         @Override
-        public RemoteViews makeBigContentView() {
-            return makeMessagingView(StandardTemplateParams.VIEW_TYPE_BIG);
+        public RemoteViews makeExpandedContentView() {
+            return makeMessagingView(StandardTemplateParams.VIEW_TYPE_EXPANDED);
         }
 
         /**
          * Create a messaging layout.
          *
-         * @param viewType one of StandardTemplateParams.VIEW_TYPE_NORMAL, VIEW_TYPE_BIG,
+         * @param viewType one of StandardTemplateParams.VIEW_TYPE_NORMAL, VIEW_TYPE_EXPANDEDIG,
          *                VIEW_TYPE_HEADS_UP
          * @return the created remoteView.
          */
         @NonNull
         private RemoteViews makeMessagingView(int viewType) {
-            boolean isCollapsed = viewType != StandardTemplateParams.VIEW_TYPE_BIG;
+            boolean isCollapsed = viewType != StandardTemplateParams.VIEW_TYPE_EXPANDED;
             boolean hideRightIcons = viewType != StandardTemplateParams.VIEW_TYPE_NORMAL;
             boolean isConversationLayout = mConversationType != CONVERSATION_TYPE_LEGACY;
             boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT;
@@ -9414,8 +9489,8 @@
                     isConversationLayout
                             ? mBuilder.getConversationLayoutResource()
                             : isCollapsed
-                                    ? mBuilder.getMessagingLayoutResource()
-                                    : mBuilder.getBigMessagingLayoutResource(),
+                                    ? mBuilder.getCollapsedMessagingLayoutResource()
+                                    : mBuilder.getExpandedMessagingLayoutResource(),
                     p,
                     bindResult);
             if (isConversationLayout) {
@@ -10038,7 +10113,7 @@
         }
 
         /**
-         * Overrides ContentTitle in the big form of the template.
+         * Overrides ContentTitle in the expanded form of the template.
          * This defaults to the value passed to setContentTitle().
          */
         public InboxStyle setBigContentTitle(CharSequence title) {
@@ -10047,7 +10122,7 @@
         }
 
         /**
-         * Set the first line of text after the detail section in the big form of the template.
+         * Set the first line of text after the detail section in the expanded form of the template.
          */
         public InboxStyle setSummaryText(CharSequence cs) {
             internalSetSummaryText(safeCharSequence(cs));
@@ -10095,9 +10170,9 @@
         /**
          * @hide
          */
-        public RemoteViews makeBigContentView() {
+        public RemoteViews makeExpandedContentView() {
             StandardTemplateParams p = mBuilder.mParams.reset()
-                    .viewType(StandardTemplateParams.VIEW_TYPE_BIG)
+                    .viewType(StandardTemplateParams.VIEW_TYPE_EXPANDED)
                     .fillTextsFrom(mBuilder).text(null);
             TemplateBindResult result = new TemplateBindResult();
             RemoteViews contentView = getStandardView(mBuilder.getInboxLayoutResource(), p, result);
@@ -10352,8 +10427,8 @@
          * @hide
          */
         @Override
-        public RemoteViews makeBigContentView() {
-            return makeMediaBigContentView(null /* customContent */);
+        public RemoteViews makeExpandedContentView() {
+            return makeMediaExpandedContentView(null /* customContent */);
         }
 
         /**
@@ -10468,7 +10543,7 @@
                     .fillTextsFrom(mBuilder);
             TemplateBindResult result = new TemplateBindResult();
             RemoteViews template = mBuilder.applyStandardTemplate(
-                    R.layout.notification_template_material_media, p,
+                    mBuilder.getCollapsedMediaLayoutResource(), p,
                     null /* result */);
 
             for (int i = 0; i < MAX_MEDIA_BUTTONS_IN_COMPACT; i++) {
@@ -10489,15 +10564,15 @@
         }
 
         /** @hide */
-        protected RemoteViews makeMediaBigContentView(@Nullable RemoteViews customContent) {
+        protected RemoteViews makeMediaExpandedContentView(@Nullable RemoteViews customContent) {
             final int actionCount = Math.min(mBuilder.mActions.size(), MAX_MEDIA_BUTTONS);
             StandardTemplateParams p = mBuilder.mParams.reset()
-                    .viewType(StandardTemplateParams.VIEW_TYPE_BIG)
+                    .viewType(StandardTemplateParams.VIEW_TYPE_EXPANDED)
                     .hideProgress(true)
                     .fillTextsFrom(mBuilder);
             TemplateBindResult result = new TemplateBindResult();
             RemoteViews template = mBuilder.applyStandardTemplate(
-                    R.layout.notification_template_material_big_media, p , result);
+                    mBuilder.getExpandedMediaLayoutResource(), p , result);
 
             for (int i = 0; i < MAX_MEDIA_BUTTONS; i++) {
                 if (i < actionCount) {
@@ -10798,8 +10873,8 @@
         /**
          * @hide
          */
-        public RemoteViews makeBigContentView() {
-            return makeCallLayout(StandardTemplateParams.VIEW_TYPE_BIG);
+        public RemoteViews makeExpandedContentView() {
+            return makeCallLayout(StandardTemplateParams.VIEW_TYPE_EXPANDED);
         }
 
         @NonNull
@@ -10920,10 +10995,10 @@
             final RemoteViews contentView;
             if (isCollapsed) {
                 contentView = mBuilder.applyStandardTemplate(
-                        R.layout.notification_template_material_call, p, null /* result */);
+                        mBuilder.getCollapsedCallLayoutResource(), p, null /* result */);
             } else {
                 contentView = mBuilder.applyStandardTemplateWithActions(
-                        R.layout.notification_template_material_big_call, p, null /* result */);
+                    mBuilder.getExpandedCallLayoutResource(), p, null /* result */);
             }
 
             // Bind some extra conversation-specific header fields.
@@ -11545,7 +11620,7 @@
                     .hideProgress(true)
                     .fillTextsFrom(mBuilder);
 
-            return getStandardView(mBuilder.getBaseLayoutResource(), p, null /* result */);
+            return getStandardView(mBuilder.getCollapsedBaseLayoutResource(), p, null /* result */);
         }
         /**
          * @hide
@@ -11563,9 +11638,9 @@
          * @hide
          */
         @Override
-        public RemoteViews makeBigContentView() {
+        public RemoteViews makeExpandedContentView() {
             StandardTemplateParams p = mBuilder.mParams.reset()
-                    .viewType(StandardTemplateParams.VIEW_TYPE_BIG)
+                    .viewType(StandardTemplateParams.VIEW_TYPE_EXPANDED)
                     .allowTextWithProgress(true)
                     .hideProgress(true)
                     .fillTextsFrom(mBuilder);
@@ -12009,8 +12084,8 @@
          * @hide
          */
         @Override
-        public RemoteViews makeBigContentView() {
-            return makeDecoratedBigContentView();
+        public RemoteViews makeExpandedContentView() {
+            return makeDecoratedExpandedContentView();
         }
 
         /**
@@ -12053,13 +12128,13 @@
                     .decorationType(StandardTemplateParams.DECORATION_PARTIAL)
                     .fillTextsFrom(mBuilder);
             RemoteViews remoteViews = mBuilder.applyStandardTemplate(
-                    mBuilder.getBaseLayoutResource(), p, result);
+                    mBuilder.getCollapsedBaseLayoutResource(), p, result);
             buildCustomContentIntoTemplate(mBuilder.mContext, remoteViews, customContent,
                     p, result);
             return remoteViews;
         }
 
-        private RemoteViews makeDecoratedBigContentView() {
+        private RemoteViews makeDecoratedExpandedContentView() {
             RemoteViews bigContentView = mBuilder.mN.bigContentView == null
                     ? mBuilder.mN.contentView
                     : mBuilder.mN.bigContentView;
@@ -12068,11 +12143,11 @@
             }
             TemplateBindResult result = new TemplateBindResult();
             StandardTemplateParams p = mBuilder.mParams.reset()
-                    .viewType(StandardTemplateParams.VIEW_TYPE_BIG)
+                    .viewType(StandardTemplateParams.VIEW_TYPE_EXPANDED)
                     .decorationType(StandardTemplateParams.DECORATION_PARTIAL)
                     .fillTextsFrom(mBuilder);
             RemoteViews remoteViews = mBuilder.applyStandardTemplateWithActions(
-                    mBuilder.getBigBaseLayoutResource(), p, result);
+                    mBuilder.getExpandedBaseLayoutResource(), p, result);
             buildCustomContentIntoTemplate(mBuilder.mContext, remoteViews, bigContentView,
                     p, result);
             return remoteViews;
@@ -12145,11 +12220,11 @@
          * @hide
          */
         @Override
-        public RemoteViews makeBigContentView() {
+        public RemoteViews makeExpandedContentView() {
             RemoteViews customContent = mBuilder.mN.bigContentView != null
                     ? mBuilder.mN.bigContentView
                     : mBuilder.mN.contentView;
-            return makeMediaBigContentView(customContent);
+            return makeMediaExpandedContentView(customContent);
         }
 
         /**
@@ -12160,7 +12235,7 @@
             RemoteViews customContent = mBuilder.mN.headsUpContentView != null
                     ? mBuilder.mN.headsUpContentView
                     : mBuilder.mN.contentView;
-            return makeMediaBigContentView(customContent);
+            return makeMediaExpandedContentView(customContent);
         }
 
         /**
@@ -14486,7 +14561,7 @@
 
         public static int VIEW_TYPE_UNSPECIFIED = 0;
         public static int VIEW_TYPE_NORMAL = 1;
-        public static int VIEW_TYPE_BIG = 2;
+        public static int VIEW_TYPE_EXPANDED = 2;
         public static int VIEW_TYPE_HEADS_UP = 3;
         public static int VIEW_TYPE_MINIMIZED = 4;    // header only for minimized state
         public static int VIEW_TYPE_PUBLIC = 5;       // header only for automatic public version
@@ -14774,12 +14849,23 @@
                 } else {
                     mBackgroundColor = rawColor;
                 }
-                mPrimaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
-                        ContrastColorUtil.resolvePrimaryColor(ctx, mBackgroundColor, nightMode),
-                        mBackgroundColor, 4.5);
-                mSecondaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
-                        ContrastColorUtil.resolveSecondaryColor(ctx, mBackgroundColor, nightMode),
-                        mBackgroundColor, 4.5);
+                if (Flags.uiRichOngoing()) {
+                    boolean isBgDark = Notification.Builder.isColorDark(mBackgroundColor);
+                    int onSurfaceColorExtreme = isBgDark ? Color.WHITE : Color.BLACK;
+                    mPrimaryTextColor = ContrastColorUtil.ensureContrast(
+                            ColorUtils.blendARGB(mBackgroundColor, onSurfaceColorExtreme, 0.9f),
+                            mBackgroundColor, isBgDark, 4.5);
+                    mSecondaryTextColor = ContrastColorUtil.ensureContrast(
+                            ColorUtils.blendARGB(mBackgroundColor, onSurfaceColorExtreme, 0.8f),
+                            mBackgroundColor, isBgDark, 4.5);
+                } else {
+                    mPrimaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
+                            ContrastColorUtil.resolvePrimaryColor(ctx, mBackgroundColor, nightMode),
+                            mBackgroundColor, 4.5);
+                    mSecondaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
+                            ContrastColorUtil.resolveSecondaryColor(ctx,
+                                    mBackgroundColor, nightMode), mBackgroundColor, 4.5);
+                }
                 mContrastColor = mPrimaryTextColor;
                 mPrimaryAccentColor = mPrimaryTextColor;
                 mSecondaryAccentColor = mSecondaryTextColor;
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index c310f95..87c8619 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1868,6 +1868,19 @@
     /**
      * @hide
      */
+    @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+    public void setTypeAdjustmentForPackageState(@NonNull String pkg, boolean enabled) {
+        INotificationManager service = getService();
+        try {
+            service.setTypeAdjustmentForPackageState(pkg, enabled);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @hide
+     */
     public List<String> getEnabledNotificationListenerPackages() {
         INotificationManager service = getService();
         try {
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index e218418..3973c58 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -61,6 +61,8 @@
 import java.util.Set;
 import java.util.WeakHashMap;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicLong;
 
 /**
@@ -680,12 +682,17 @@
         @GuardedBy("mLock")
         private boolean mTestMode = false;
 
-        /**
-         * The local value of the handler, used during testing but also used directly by the
-         * NonceLocal handler.
-         */
+        // This is the local value of the nonce, as last set by the NonceHandler.  It is always
+        // updated by the setNonce() operation.  The getNonce() operation returns this value in
+        // NonceLocal handlers and handlers in test mode.
         @GuardedBy("mLock")
-        protected long mTestNonce = NONCE_UNSET;
+        protected long mShadowNonce = NONCE_UNSET;
+
+        // A list of watchers to be notified of changes.  This is null until at least one watcher
+        // registers.  Checking for null is meant to be the fastest way the handler can determine
+        // that there are no watchers to be notified.
+        @GuardedBy("mLock")
+        private ArrayList<Semaphore> mWatchers;
 
         /**
          * The methods to get and set a nonce from whatever storage is being used.  mLock may be
@@ -701,27 +708,60 @@
 
         /**
          * Get a nonce from storage.  If the handler is in test mode, the nonce is returned from
-         * the local mTestNonce.
+         * the local mShadowNonce.
          */
         long getNonce() {
             synchronized (mLock) {
-                if (mTestMode) return mTestNonce;
+                if (mTestMode) return mShadowNonce;
             }
             return getNonceInternal();
         }
 
         /**
-         * Write a nonce to storage.  If the handler is in test mode, the nonce is written to the
-         * local mTestNonce and storage is not affected.
+         * Write a nonce to storage.  The nonce is always written to the local mShadowNonce.  If
+         * the handler is not in test mode the nonce is also written to storage.
          */
         void setNonce(long val) {
             synchronized (mLock) {
-                if (mTestMode) {
-                    mTestNonce = val;
-                    return;
+                mShadowNonce = val;
+                if (!mTestMode) {
+                    setNonceInternal(val);
+                }
+                wakeAllWatchersLocked();
+            }
+        }
+
+        @GuardedBy("mLock")
+        private void wakeAllWatchersLocked() {
+            if (mWatchers != null) {
+                for (int i = 0; i < mWatchers.size(); i++) {
+                    mWatchers.get(i).release();
                 }
             }
-            setNonceInternal(val);
+        }
+
+        /**
+         * Register a watcher to be notified when a nonce changes.  There is no check for
+         * duplicates.  In general, this method is called only from {@link NonceWatcher}.
+         */
+        void registerWatcher(Semaphore s) {
+            synchronized (mLock) {
+                if (mWatchers == null) {
+                    mWatchers = new ArrayList<>();
+                }
+                mWatchers.add(s);
+            }
+        }
+
+        /**
+         * Unregister a watcher.  Nothing happens if the watcher is not registered.
+         */
+        void unregisterWatcher(Semaphore s) {
+            synchronized (mLock) {
+                if (mWatchers != null) {
+                    mWatchers.remove(s);
+                }
+            }
         }
 
         /**
@@ -854,7 +894,7 @@
         void setTestMode(boolean mode) {
             synchronized (mLock) {
                 mTestMode = mode;
-                mTestNonce = NONCE_UNSET;
+                mShadowNonce = NONCE_UNSET;
             }
         }
 
@@ -1028,7 +1068,7 @@
     /**
      * SystemProperties and shared storage are protected and cannot be written by random
      * processes.  So, for testing purposes, the NonceLocal handler stores the nonce locally.  The
-     * NonceLocal uses the mTestNonce in the superclass, regardless of test mode.
+     * NonceLocal uses the mShadowNonce in the superclass, regardless of test mode.
      */
     private static class NonceLocal extends NonceHandler {
         // The saved nonce.
@@ -1040,16 +1080,130 @@
 
         @Override
         long getNonceInternal() {
-            return mTestNonce;
+            return mShadowNonce;
         }
 
         @Override
         void setNonceInternal(long value) {
-            mTestNonce = value;
+            mShadowNonce = value;
         }
     }
 
     /**
+     * A NonceWatcher lets an external client test if a nonce value has changed from the last time
+     * the watcher was checked.
+     * @hide
+     */
+    public static class NonceWatcher implements AutoCloseable {
+        // The handler for the key.
+        private final NonceHandler mHandler;
+
+        // The last-seen value.  This is initialized to "unset".
+        private long mLastSeen = NONCE_UNSET;
+
+        // The semaphore that the watcher waits on.  A permit is released every time the nonce
+        // changes.  Permits are acquired in the wait method.
+        private final Semaphore mSem = new Semaphore(0);
+
+        /**
+         * Create a watcher for a handler.  The last-seen value is not set here and will be
+         * "unset".  Therefore, a call to isChanged() will return true if the nonce has ever been
+         * set, no matter when the watcher is first created.  Clients may want to flush that
+         * change by calling isChanged() immediately after constructing the object.
+         */
+        private NonceWatcher(@NonNull NonceHandler handler) {
+            mHandler = handler;
+            mHandler.registerWatcher(mSem);
+        }
+
+        /**
+         * Unregister to be notified when a nonce changes.  NonceHandler allows a call to
+         * unregisterWatcher with a semaphore that is not registered, so there is no check inside
+         * this method to guard against multiple closures.
+         */
+        @Override
+        public void close() {
+            mHandler.unregisterWatcher(mSem);
+        }
+
+        /**
+         * Return the last seen value of the nonce.  This does not update that value.  Only
+         * {@link #isChanged()} updates the value.
+         */
+        public long lastSeen() {
+            return mLastSeen;
+        }
+
+        /**
+         * Return true if the nonce has changed from the last time isChanged() was called.  The
+         * method is not thread safe.
+         * @hide
+         */
+        public boolean isChanged() {
+            long current = mHandler.getNonce();
+            if (current != mLastSeen) {
+                mLastSeen = current;
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Wait for the nonce value to change.  It is not guaranteed that the nonce has changed when
+         * this returns: clients must confirm with {@link #isChanged}. The wait operation is only
+         * effective in a process that writes the nonces.  The function returns the number of times
+         * the nonce had changed since the last call to the method.
+         * @hide
+         */
+        public int waitForChange() throws InterruptedException {
+            mSem.acquire(1);
+            return 1 + mSem.drainPermits();
+        }
+
+        /**
+         * Wait for the nonce value to change.  It is not guaranteed that the nonce has changed when
+         * this returns: clients must confirm with {@link #isChanged}. The wait operation is only
+         * effective in a process that writes the nonces.  The function returns the number of times
+         * the nonce changed since the last call to the method.  A return value of zero means the
+         * timeout expired.  Beware that a timeout of 0 means the function will not wait at all.
+         * @hide
+         */
+        public int waitForChange(long timeout, TimeUnit timeUnit) throws InterruptedException {
+            if (mSem.tryAcquire(1, timeout, timeUnit)) {
+                return 1 + mSem.drainPermits();
+            } else {
+                return 0;
+            }
+        }
+
+        /**
+         * Wake the watcher by releasing the semaphore.  This can be used to wake clients that are
+         * blocked in {@link #waitForChange} without affecting the underlying nonce.
+         * @hide
+         */
+        public void wakeUp() {
+            mSem.release();
+        }
+    }
+
+    /**
+     * Return a NonceWatcher for the cache.
+     * @hide
+     */
+    public NonceWatcher getNonceWatcher() {
+        return new NonceWatcher(mNonce);
+    }
+
+    /**
+     * Return a NonceWatcher for the given property.  If a handler does not exist for the
+     * property, one is created.  This throws if the property name is not a valid cache key.
+     * @hide
+     */
+    public static NonceWatcher getNonceWatcher(@NonNull String propertyName) {
+        return new NonceWatcher(getNonceHandler(propertyName));
+    }
+
+    /**
      * Complete key prefixes.
      */
     private static final String PREFIX_TEST = CACHE_KEY_PREFIX + "." + MODULE_TEST + ".";
@@ -1663,6 +1817,26 @@
     }
 
     /**
+     * Non-static version of corkInvalidations() for situations in which the cache instance is
+     * available.  This is slightly faster than than the static versions because it does not have
+     * to look up the NonceHandler for a given property name.
+     * @hide
+     */
+    public void corkInvalidations() {
+        mNonce.cork();
+    }
+
+    /**
+     * Non-static version of uncorkInvalidations() for situations in which the cache instance is
+     * available.  This is slightly faster than than the static versions because it does not have
+     * to look up the NonceHandler for a given property name.
+     * @hide
+     */
+    public void uncorkInvalidations() {
+        mNonce.uncork();
+    }
+
+    /**
      * Invalidate caches in all processes that are keyed for the module and api.
      * @hide
      */
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 5ed1f4e..637187e 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -177,6 +177,10 @@
         {
             "file_patterns": ["(/|^)AppOpsManager.java"],
             "name": "CtsAppOpsTestCases"
+        },
+        {
+            "file_patterns": ["(/|^)BroadcastStickyCache.java"],
+            "name": "BroadcastUnitTests"
         }
     ]
 }
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index 36f61fd..b9b582a 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -198,6 +198,10 @@
     }
 
     @Override
+    public void onRecentTaskRemovedForAddTask(int taskId) {
+    }
+
+    @Override
     public void onTaskFocusChanged(int taskId, boolean focused) {
     }
 
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index abb2dd4..a8671cf 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -2491,6 +2491,27 @@
         return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
     }
 
+    /**
+     * Version of setBitmap that allows specification of wallpaper metadata including how the
+     * wallpaper will be positioned for different display sizes.
+     *
+     * @param fullImage   A bitmap that will supply the wallpaper imagery.
+     * @param description Wallpaper metadata including desired cropping
+     * @param allowBackup {@code true} if the OS is permitted to back up this wallpaper
+     *                    image for restore to a future device; {@code false} otherwise.
+     * @param which       Flags indicating which wallpaper(s) to configure with the new imagery.
+     * @hide
+     */
+    @FlaggedApi(FLAG_LIVE_WALLPAPER_CONTENT_HANDLING)
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
+    public int setBitmapWithDescription(@Nullable Bitmap fullImage,
+            @NonNull WallpaperDescription description, boolean allowBackup,
+            @SetWallpaperFlags int which) throws IOException {
+        return setBitmapWithCrops(fullImage, description.getCropHints(), allowBackup, which,
+                mContext.getUserId());
+    }
+
     private final void validateRect(Rect rect) {
         if (rect != null && rect.isEmpty()) {
             throw new IllegalArgumentException("visibleCrop rectangle must be valid and non-empty");
@@ -2700,6 +2721,27 @@
     }
 
     /**
+     * Version of setStream that allows specification of wallpaper metadata including how the
+     * wallpaper will be positioned for different display sizes.
+     *
+     * @param bitmapData  A stream containing the raw data to install as a wallpaper. This
+     *                    data can be in any format handled by {@link BitmapRegionDecoder}.
+     * @param description Wallpaper metadata including desired cropping
+     * @param allowBackup {@code true} if the OS is permitted to back up this wallpaper
+     *                    image for restore to a future device; {@code false} otherwise.
+     * @param which       Flags indicating which wallpaper(s) to configure with the new imagery.
+     * @hide
+     */
+    @FlaggedApi(FLAG_LIVE_WALLPAPER_CONTENT_HANDLING)
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
+    public int setStreamWithDescription(@NonNull InputStream bitmapData,
+            @NonNull WallpaperDescription description, boolean allowBackup,
+            @SetWallpaperFlags int which) throws IOException {
+        return setStreamWithCrops(bitmapData, description.getCropHints(), allowBackup, which);
+    }
+
+    /**
      * Return whether any users are currently set to use the wallpaper
      * with the given resource ID.  That is, their wallpaper has been
      * set through {@link #setResource(int)} with the same resource id.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e766ae2..74d7298 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4177,6 +4177,35 @@
         }
     }
 
+
+    /**
+     * Similar to the public variant of {@link #setMtePolicy} but for use by the system.
+     *
+     * <p>Called by a system service only, meaning that the caller's UID must be equal to
+     * {@link Process#SYSTEM_UID}.
+     *
+     * @throws SecurityException if caller is not permitted to set Mte policy
+     * @throws UnsupportedOperationException if the device does not support MTE
+     * @param systemEntity  The service entity that adds the restriction. A user restriction set by
+     *                       a service entity can only be cleared by the same entity. This can be
+     *                       just the calling package name, or any string of the caller's choice
+     *                       can be used.
+     * @param policy the MTE policy to be set
+     * @hide
+     */
+    public void setMtePolicy(@NonNull String systemEntity, @MtePolicy int policy) {
+        throwIfParentInstance("setMtePolicyForUser");
+        if (mService != null) {
+            try {
+                mService.setMtePolicyBySystem(systemEntity, policy);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+
+
     /**
      * Called by a device owner, profile owner of an organization-owned device to
      * get the Memory Tagging Extension (MTE) policy
@@ -14453,7 +14482,7 @@
      * </ul>
      * <p>
      * The following methods are supported for the parent instance but can only be called by the
-     * profile owner of a managed profile that was created during the device provisioning flow:
+     * profile owner on an <a href="#organization-owned">organization owned</a> managed profile:
      * <ul>
      * <li>{@link #getPasswordComplexity}</li>
      * <li>{@link #setCameraDisabled}</li>
@@ -14461,11 +14490,6 @@
      * <li>{@link #setAccountManagementDisabled(ComponentName, String, boolean)}</li>
      * <li>{@link #setPermittedInputMethods}</li>
      * <li>{@link #getPermittedInputMethods}</li>
-     * </ul>
-     *
-     * <p>The following methods can be called by the profile owner of a managed profile
-     * on an organization-owned device:
-     * <ul>
      * <li>{@link #wipeData}</li>
      * </ul>
      *
@@ -18177,4 +18201,4 @@
         }
         return HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED;
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index d048b53..e7be822 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -617,6 +617,7 @@
     int[] getApplicationExemptions(String packageName);
 
     void setMtePolicy(int flag, String callerPackageName);
+    void setMtePolicyBySystem(in String systemEntity, int policy);
     int getMtePolicy(String callerPackageName);
 
     void setManagedSubscriptionsPolicy(in ManagedSubscriptionsPolicy policy);
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 581efa5..686c830 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -387,6 +387,7 @@
 
 flag {
   name: "split_create_managed_profile_enabled"
+  is_exported: true
   namespace: "enterprise"
   description: "Split up existing create and provision managed profile API."
   bug: "375382324"
diff --git a/core/java/android/app/background_install_control_manager.aconfig b/core/java/android/app/background_install_control_manager.aconfig
index d29c5b5..39f10dc 100644
--- a/core/java/android/app/background_install_control_manager.aconfig
+++ b/core/java/android/app/background_install_control_manager.aconfig
@@ -9,3 +9,10 @@
      is_fixed_read_only: true
      bug: "287507984"
 }
+
+flag {
+    name: "background_install_control_callback_api"
+    namespace: "preload_safety"
+    description: "Feature flag to enable the use of push API in background install control service"
+    bug: "369382811"
+}
\ No newline at end of file
diff --git a/core/java/android/app/wallpaper/WallpaperDescription.java b/core/java/android/app/wallpaper/WallpaperDescription.java
index 4a142bb..3ee00ca 100644
--- a/core/java/android/app/wallpaper/WallpaperDescription.java
+++ b/core/java/android/app/wallpaper/WallpaperDescription.java
@@ -19,8 +19,14 @@
 import static android.app.Flags.FLAG_LIVE_WALLPAPER_CONTENT_HANDLING;
 
 import android.annotation.FlaggedApi;
+import android.annotation.SuppressLint;
+import android.annotation.TestApi;
 import android.app.WallpaperInfo;
+import android.app.WallpaperManager;
+import android.app.WallpaperManager.ScreenOrientation;
 import android.content.ComponentName;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -29,6 +35,8 @@
 import android.text.Spanned;
 import android.text.SpannedString;
 import android.util.Log;
+import android.util.Pair;
+import android.util.SparseArray;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -43,6 +51,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -71,12 +80,15 @@
     @Nullable private final Uri mContextUri;
     @Nullable private final CharSequence mContextDescription;
     @NonNull private final PersistableBundle mContent;
+    @NonNull private final SparseArray<Rect> mCropHints;
+    private final float mSampleSize;
 
     private WallpaperDescription(@Nullable ComponentName component,
             @Nullable String id, @Nullable Uri thumbnail, @Nullable CharSequence title,
             @Nullable List<CharSequence> description, @Nullable Uri contextUri,
             @Nullable CharSequence contextDescription,
-            @Nullable PersistableBundle content) {
+            @Nullable PersistableBundle content, @NonNull SparseArray<Rect> cropHints,
+            float sampleSize) {
         this.mComponent = component;
         this.mId = id;
         this.mThumbnail = thumbnail;
@@ -85,6 +97,8 @@
         this.mContextUri = contextUri;
         this.mContextDescription = contextDescription;
         this.mContent = (content != null) ? content : new PersistableBundle();
+        this.mCropHints = cropHints;
+        this.mSampleSize = sampleSize;
     }
 
     /** @return the component for this wallpaper, or {@code null} for a static wallpaper */
@@ -134,6 +148,24 @@
         return mContent;
     }
 
+    /**
+     * @return the cropping for the current image as described in
+     * {@link Builder#setCropHints(SparseArray)}
+     * @hide
+     */
+    @NonNull
+    public SparseArray<Rect> getCropHints() {
+        return mCropHints;
+    }
+
+    /**
+     * @return the subsamling size as described in {@link Builder#setSampleSize(float)}.
+     * @hide
+     */
+    public float getSampleSize() {
+        return mSampleSize;
+    }
+
     ////// Comparison overrides
 
     @Override
@@ -163,9 +195,23 @@
         if (mContextDescription != null) {
             out.attribute(null, "contextdescription", toHtml(mContextDescription));
         }
+
+        for (Pair<Integer, String> pair : screenDimensionPairs()) {
+            @ScreenOrientation int orientation = pair.first;
+            String attrName = pair.second;
+            Rect cropHint = mCropHints.get(orientation);
+            if (cropHint == null) continue;
+            out.attributeInt(null, "cropLeft" + attrName, cropHint.left);
+            out.attributeInt(null, "cropTop" + attrName, cropHint.top);
+            out.attributeInt(null, "cropRight" + attrName, cropHint.right);
+            out.attributeInt(null, "cropBottom" + attrName, cropHint.bottom);
+        }
+        out.attributeFloat(null, "sampleSize", mSampleSize);
+
         out.startTag(null, XML_TAG_DESCRIPTION);
         for (CharSequence s : mDescription) out.attribute(null, "descriptionline", toHtml(s));
         out.endTag(null, XML_TAG_DESCRIPTION);
+
         try {
             out.startTag(null, XML_TAG_CONTENT);
             mContent.saveToXml(out);
@@ -194,6 +240,19 @@
         CharSequence contextDescription = fromHtml(
                 in.getAttributeValue(null, "contextdescription"));
 
+        SparseArray<Rect> cropHints = new SparseArray<>();
+        screenDimensionPairs().forEach(pair -> {
+            @ScreenOrientation int orientation = pair.first;
+            String attrName = pair.second;
+            Rect crop = new Rect(
+                    in.getAttributeInt(null, "cropLeft" + attrName, 0),
+                    in.getAttributeInt(null, "cropTop" + attrName, 0),
+                    in.getAttributeInt(null, "cropRight" + attrName, 0),
+                    in.getAttributeInt(null, "cropBottom" + attrName, 0));
+            if (!crop.isEmpty()) cropHints.put(orientation, crop);
+        });
+        float sampleSize = in.getAttributeFloat(null, "sampleSize", 1f);
+
         List<CharSequence> description = new ArrayList<>();
         PersistableBundle content = null;
         int type;
@@ -213,7 +272,7 @@
         }
 
         return new WallpaperDescription(componentName, id, thumbnail, title, description,
-                contextUri, contextDescription, content);
+                contextUri, contextDescription, content, cropHints, sampleSize);
     }
 
     private static String toHtml(@NonNull CharSequence c) {
@@ -253,6 +312,13 @@
         mContextUri = Uri.CREATOR.createFromParcel(in);
         mContextDescription = in.readCharSequence();
         mContent = PersistableBundle.CREATOR.createFromParcel(in);
+        mCropHints = new SparseArray<>();
+        screenDimensionPairs().forEach(pair -> {
+            int orientation = pair.first;
+            Rect crop = in.readTypedObject(Rect.CREATOR);
+            if (crop != null) mCropHints.put(orientation, crop);
+        });
+        mSampleSize = in.readFloat();
     }
 
     @NonNull
@@ -283,6 +349,11 @@
         Uri.writeToParcel(dest, mContextUri);
         dest.writeCharSequence(mContextDescription);
         dest.writePersistableBundle(mContent);
+        screenDimensionPairs().forEach(pair -> {
+            int orientation = pair.first;
+            dest.writeTypedObject(mCropHints.get(orientation), flags);
+        });
+        dest.writeFloat(mSampleSize);
     }
 
     ////// Builder
@@ -293,9 +364,17 @@
      */
     @NonNull
     public Builder toBuilder() {
-        return new Builder().setComponent(mComponent).setId(mId).setThumbnail(mThumbnail).setTitle(
-                mTitle).setDescription(mDescription).setContextUri(
-                mContextUri).setContextDescription(mContextDescription).setContent(mContent);
+        return new Builder()
+                .setComponent(mComponent)
+                .setId(mId)
+                .setThumbnail(mThumbnail)
+                .setTitle(mTitle)
+                .setDescription(mDescription)
+                .setContextUri(mContextUri)
+                .setContextDescription(mContextDescription)
+                .setContent(mContent)
+                .setCropHints(mCropHints)
+                .setSampleSize(mSampleSize);
     }
 
     /** Builder for the immutable {@link WallpaperDescription} class */
@@ -308,6 +387,9 @@
         @Nullable private Uri mContextUri;
         @Nullable private CharSequence mContextDescription;
         @NonNull private PersistableBundle mContent = new PersistableBundle();
+        @NonNull
+        private SparseArray<Rect> mCropHints = new SparseArray<>();
+        private float mSampleSize = 1f;
 
         /** Creates a new, empty {@link Builder}. */
         public Builder() {}
@@ -416,11 +498,69 @@
             return this;
         }
 
+        /**
+         * Defines which part of the source wallpaper image is in the stored crop file.
+         *
+         * @param cropHints map from screen dimensions to a sub-region of the image to display
+         *                  for those dimensions. The {@code Rect} sub-region may have a larger
+         *                  width/height ratio than the screen dimensions to apply a horizontal
+         *                  parallax effect. If the map is empty or some entries are missing, the
+         *                  system will apply a default strategy to position the wallpaper for
+         *                  any unspecified screen dimensions.
+         * @hide
+         */
+        @NonNull
+        @TestApi
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public Builder setCropHints(@NonNull Map<Point, Rect> cropHints) {
+            mCropHints = new SparseArray<>();
+            cropHints.forEach(
+                    (point, rect) -> mCropHints.put(WallpaperManager.getOrientation(point), rect));
+            return this;
+        }
+
+        /**
+         * Defines which part of the source wallpaper image is in the stored crop file.
+         *
+         * @param cropHints map from {@link ScreenOrientation} to a sub-region of the image to
+         *                  display for that screen orientation.
+         * @hide
+         */
+        @NonNull
+        @TestApi
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public Builder setCropHints(@NonNull SparseArray<Rect> cropHints) {
+            mCropHints = cropHints;
+            return this;
+        }
+
+        /**
+         * How much the crop is sub-sampled. A value > 1 means that the image quality was reduced.
+         * This is the ratio between the cropHint height and the actual stored crop file height.
+         * height.
+         *
+         * @param sampleSize Sub-sampling value
+         * @hide
+         */
+        @NonNull
+        public Builder setSampleSize(float sampleSize) {
+            mSampleSize = sampleSize;
+            return this;
+        }
+
         /** Creates and returns the {@link WallpaperDescription} represented by this builder. */
         @NonNull
         public WallpaperDescription build() {
             return new WallpaperDescription(mComponent, mId, mThumbnail, mTitle, mDescription,
-                    mContextUri, mContextDescription, mContent);
+                    mContextUri, mContextDescription, mContent, mCropHints, mSampleSize);
         }
     }
+
+    private static List<Pair<Integer, String>> screenDimensionPairs() {
+        return List.of(
+                new Pair<>(WallpaperManager.ORIENTATION_PORTRAIT, "Portrait"),
+                new Pair<>(WallpaperManager.ORIENTATION_LANDSCAPE, "Landscape"),
+                new Pair<>(WallpaperManager.ORIENTATION_SQUARE_PORTRAIT, "SquarePortrait"),
+                new Pair<>(WallpaperManager.ORIENTATION_SQUARE_LANDSCAPE, "SquareLandscape"));
+    }
 }
diff --git a/core/java/android/app/wearable/WearableSensingManager.java b/core/java/android/app/wearable/WearableSensingManager.java
index f076375..5b14b03 100644
--- a/core/java/android/app/wearable/WearableSensingManager.java
+++ b/core/java/android/app/wearable/WearableSensingManager.java
@@ -55,6 +55,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
@@ -248,7 +249,11 @@
      * @param executor Executor on which to run the consumer callback
      * @param statusConsumer A consumer that handles the status codes for providing the connection
      *     and errors in the encrypted channel.
+     * @deprecated Use {@link #provideConnection(WearableConnection, Executor)} instead to provide a
+     *     remote wearable device connection to the WearableSensingService
      */
+    @FlaggedApi(Flags.FLAG_ENABLE_CONCURRENT_WEARABLE_CONNECTIONS)
+    @Deprecated
     @RequiresPermission(Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)
     public void provideConnection(
             @NonNull ParcelFileDescriptor wearableConnection,
@@ -348,9 +353,7 @@
                             wearableConnection.getMetadata(),
                             createWearableSensingCallback(executor),
                             statusCallback);
-            if (connectionId != CONNECTION_ID_INVALID) {
-                mWearableConnectionIdMap.put(wearableConnection, connectionId);
-            }
+            mWearableConnectionIdMap.put(wearableConnection, connectionId);
             // For invalid connection IDs, the status callback will remove the connection from
             // mWearableConnectionIdMap
         } catch (RemoteException e) {
@@ -367,36 +370,37 @@
      * <p>After this method returns, there will be no new invocation to callback methods in the
      * removed {@link WearableConnection}. Ongoing invocations will continue to run.
      *
-     * <p>This method does nothing if the provided {@code wearableConnection} does not match any
-     * open connection.
+     * <p>This method throws a {@link NoSuchElementException} if the provided {@code
+     * wearableConnection} does not match any open connection.
      *
      * <p>This method should not be called before the corresponding {@link
      * #provideConnection(WearableConnection, Executor)} invocation returns. Otherwise, the
-     * connection may not be removed.
+     * connection may not be removed, and an {@link IllegalStateException} may be thrown.
      *
      * @param wearableConnection The WearableConnection instance previously provided to {@link
      *     #provideConnection(WearableConnection, Executor)}.
-     * @return true if a concurrent connection quota has been freed due to this method invocation.
-     *     Returns false otherwise.
+     * @throws NoSuchElementException if the connection was never provided or was already removed.
+     * @throws IllegalStateException if the {@link #provideConnection(WearableConnection, Executor)}
+     *     invocation for the given connection has not returned.
      */
     @RequiresPermission(Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)
     @FlaggedApi(Flags.FLAG_ENABLE_CONCURRENT_WEARABLE_CONNECTIONS)
-    public boolean removeConnection(@NonNull WearableConnection wearableConnection) {
-        int connectionId =
-                mWearableConnectionIdMap.getOrDefault(wearableConnection, CONNECTION_ID_INVALID);
-        if (connectionId == CONNECTION_ID_INVALID) {
-            return false;
+    public void removeConnection(@NonNull WearableConnection wearableConnection) {
+        Integer connectionId = mWearableConnectionIdMap.remove(wearableConnection);
+        if (connectionId == null || connectionId == CONNECTION_ID_INVALID) {
+            throw new NoSuchElementException(
+                    "The provided connection was never provided or was already removed.");
         }
         if (connectionId == CONNECTION_ID_PLACEHOLDER) {
-            Slog.w(
-                    TAG,
+            throw new IllegalStateException(
                     "Attempt to remove connection before provideConnection returns. The connection"
                             + " will not be removed.");
-            return false;
         }
-        mWearableConnectionIdMap.remove(wearableConnection);
         try {
-            return mService.removeConnection(connectionId);
+            if (!mService.removeConnection(connectionId)) {
+                throw new NoSuchElementException(
+                        "The provided connection was never provided or was already removed.");
+            }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 8f20ea0..40de298 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -31,6 +31,7 @@
 import android.annotation.UserIdInt;
 import android.app.IServiceConnection;
 import android.app.PendingIntent;
+import android.app.usage.UsageStatsManager;
 import android.appwidget.flags.Flags;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
@@ -41,12 +42,14 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ShortcutInfo;
+import android.graphics.Rect;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.HandlerThread;
 import android.os.Looper;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -485,6 +488,67 @@
     public static final String ACTION_APPWIDGET_HOST_RESTORED
             = "android.appwidget.action.APPWIDGET_HOST_RESTORED";
 
+    /**
+     * This is the value of {@link UsageStatsManager.EXTRA_EVENT_ACTION} in the event bundle for
+     * widget user interaction events.
+     *
+     * A single widget interaction event describes what user interactions happened during a single
+     * impression of the widget.
+     */
+    @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS)
+    public static final String EVENT_TYPE_WIDGET_INTERACTION = "widget_interaction";
+
+    /**
+     * This is the value of {@link UsageStatsManager.EXTRA_EVENT_CATEGORY} in the event bundle for
+     * widget user interaction events.
+     */
+    @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS)
+    public static final String EVENT_CATEGORY_APPWIDGET = "android.appwidget";
+
+    /**
+     * This bundle extra describes which views have been clicked during a single impression of the
+     * widget. It is an integer array of view IDs of the clicked views.
+     *
+     * Widget providers may set a different ID for event purposes by setting the
+     * {@link android.R.id.remoteViewsMetricsId} int tag on the view.
+     *
+     * @see android.views.RemoteViews.setIntTag
+     */
+    @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS)
+    public static final String EXTRA_EVENT_CLICKED_VIEWS =
+            "android.appwidget.extra.EVENT_CLICKED_VIEWS";
+
+    /**
+     * This bundle extra describes which views have been scrolled during a single impression of the
+     * widget. It is an integer array of view IDs of the scrolled views.
+     *
+     * Widget providers may set a different ID for event purposes by setting the
+     * {@link android.R.id.remoteViewsMetricsId} int tag on the view.
+     *
+     * @see android.views.RemoteViews.setIntTag
+     */
+    @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS)
+    public static final String EXTRA_EVENT_SCROLLED_VIEWS =
+            "android.appwidget.extra.EVENT_SCROLLED_VIEWS";
+
+    /**
+     * This bundle extra contains a long that represents the duration of time in milliseconds
+     * during which the widget was visible.
+     */
+    @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS)
+    public static final String EXTRA_EVENT_DURATION_MS =
+            "android.appwidget.extra.EVENT_DURATION_MS";
+
+    /**
+     * This bundle extra contains an integer array with 4 elements that describe the left, top,
+     * right, and bottom coordinates of the widget at the end of the interaction event.
+     *
+     * This Rect indicates the current position and size of the widget.
+     */
+    @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS)
+    public static final String EXTRA_EVENT_POSITION_RECT =
+            "android.appwidget.extra.EVENT_POSITION_RECT";
+
     private static final String TAG = "AppWidgetManager";
 
     private static Executor sUpdateExecutor;
@@ -1516,6 +1580,39 @@
         }
     }
 
+    /**
+     * Create a {@link PersistableBundle} that represents a single widget interaction event.
+     *
+     * @param appWidgetId App Widget ID of the widget.
+     * @param durationMs Duration of the impression in milliseconds
+     * @param position Current position of the widget.
+     * @param clickedIds IDs of views clicked during this event.
+     * @param scrolledIds IDs of views scrolled during this event.
+     *
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS)
+    @NonNull
+    public static PersistableBundle createWidgetInteractionEvent(int appWidgetId, long durationMs,
+            @Nullable Rect position, @Nullable int[] clickedIds, @Nullable int[] scrolledIds) {
+        PersistableBundle extras = new PersistableBundle();
+        extras.putString(UsageStatsManager.EXTRA_EVENT_ACTION, EVENT_TYPE_WIDGET_INTERACTION);
+        extras.putString(UsageStatsManager.EXTRA_EVENT_CATEGORY, EVENT_CATEGORY_APPWIDGET);
+        extras.putInt(EXTRA_APPWIDGET_ID, appWidgetId);
+        extras.putLong(EXTRA_EVENT_DURATION_MS, durationMs);
+        if (position != null) {
+            extras.putIntArray(EXTRA_EVENT_POSITION_RECT,
+                    new int[]{position.left, position.top, position.right, position.bottom});
+        }
+        if (clickedIds != null && clickedIds.length > 0) {
+            extras.putIntArray(EXTRA_EVENT_CLICKED_VIEWS, clickedIds);
+        }
+        if (scrolledIds != null && scrolledIds.length > 0) {
+            extras.putIntArray(EXTRA_EVENT_SCROLLED_VIEWS, scrolledIds);
+        }
+        return extras;
+    }
+
 
     @UiThread
     private static @NonNull Executor createUpdateExecutorIfNull() {
diff --git a/core/java/android/appwidget/flags.aconfig b/core/java/android/appwidget/flags.aconfig
index 4499a72..17bcdb0 100644
--- a/core/java/android/appwidget/flags.aconfig
+++ b/core/java/android/appwidget/flags.aconfig
@@ -105,3 +105,10 @@
     purpose: PURPOSE_BUGFIX
   }
 }
+
+flag {
+  name: "engagement_metrics"
+  namespace: "app_widgets"
+  description: "Enable collection of widget engagement metrics"
+  bug: "364655296"
+}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 4472c3d..0466847 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -1229,7 +1229,6 @@
         }
     }
 
-    // TODO(b/315163162) Add @Deprecated keyword after 24Q2 cut.
     /**
      * Register to receive callbacks whenever the associated device comes in and out of range.
      *
@@ -1261,7 +1260,12 @@
      *
      * @throws DeviceNotAssociatedException if the given device was not previously associated
      * with this app.
+     *
+     * @deprecated use {@link #startObservingDevicePresence(ObservingDevicePresenceRequest)}
+     * instead.
      */
+    @FlaggedApi(Flags.FLAG_DEVICE_PRESENCE)
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE)
     public void startObservingDevicePresence(@NonNull String deviceAddress)
             throws DeviceNotAssociatedException {
@@ -1288,7 +1292,7 @@
                             callingUid, callingPid);
         }
     }
-    // TODO(b/315163162) Add @Deprecated keyword after 24Q2 cut.
+
     /**
      * Unregister for receiving callbacks whenever the associated device comes in and out of range.
      *
@@ -1305,7 +1309,12 @@
      *
      * @throws DeviceNotAssociatedException if the given device was not previously associated
      * with this app.
+     *
+     * @deprecated use {@link #stopObservingDevicePresence(ObservingDevicePresenceRequest)}
+     * instead.
      */
+    @FlaggedApi(Flags.FLAG_DEVICE_PRESENCE)
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE)
     public void stopObservingDevicePresence(@NonNull String deviceAddress)
             throws DeviceNotAssociatedException {
diff --git a/core/java/android/companion/CompanionDeviceService.java b/core/java/android/companion/CompanionDeviceService.java
index 5ad2348..316d129 100644
--- a/core/java/android/companion/CompanionDeviceService.java
+++ b/core/java/android/companion/CompanionDeviceService.java
@@ -247,12 +247,14 @@
                 .detachSystemDataTransport(associationId);
     }
 
-    // TODO(b/315163162) Add @Deprecated keyword after 24Q2 cut.
     /**
-     * Called by system whenever a device associated with this app is connected.
+     * Called by the system when an associated device is nearby or connected.
      *
      * @param associationInfo A record for the companion device.
+     * @deprecated use {@link #onDevicePresenceEvent(DevicePresenceEvent)}} instead.
      */
+    @FlaggedApi(Flags.FLAG_DEVICE_PRESENCE)
+    @Deprecated
     @MainThread
     public void onDeviceAppeared(@NonNull AssociationInfo associationInfo) {
         if (!associationInfo.isSelfManaged()) {
@@ -260,12 +262,14 @@
         }
     }
 
-    // TODO(b/315163162) Add @Deprecated keyword after 24Q2 cut.
     /**
-     * Called by system whenever a device associated with this app is disconnected.
+     * Called by the system when an associated device is out of range or disconnected.
      *
      * @param associationInfo A record for the companion device.
+     * @deprecated use {@link #onDevicePresenceEvent(DevicePresenceEvent)}} instead.
      */
+    @FlaggedApi(Flags.FLAG_DEVICE_PRESENCE)
+    @Deprecated
     @MainThread
     public void onDeviceDisappeared(@NonNull AssociationInfo associationInfo) {
         if (!associationInfo.isSelfManaged()) {
@@ -274,7 +278,7 @@
     }
 
     /**
-     * Called by the system during device events.
+     * Called by the system when an associated device's presence state changes.
      *
      * @see CompanionDeviceManager#startObservingDevicePresence(ObservingDevicePresenceRequest)
      */
diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl
index d3a1c25..f8ac27d 100644
--- a/core/java/android/companion/virtual/IVirtualDevice.aidl
+++ b/core/java/android/companion/virtual/IVirtualDevice.aidl
@@ -96,6 +96,7 @@
     boolean canCreateMirrorDisplays();
 
     /*
+    /*
      * Turns off all trusted non-mirror displays of the virtual device.
      */
     void goToSleep();
diff --git a/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl b/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl
index 767f52a..448793d 100644
--- a/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl
+++ b/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl
@@ -63,4 +63,11 @@
      * @param user The user associated with the activity.
      */
     void onSecureWindowShown(int displayId, in ComponentName componentName, in UserHandle user);
+
+    /**
+     * Called when a secure surface is no longer shown on the device.
+     *
+     * @param displayId The display ID on which the secure surface was shown.
+     */
+    void onSecureWindowHidden(int displayId);
 }
diff --git a/core/java/android/companion/virtual/VirtualDeviceInternal.java b/core/java/android/companion/virtual/VirtualDeviceInternal.java
index d63a443..42c7441 100644
--- a/core/java/android/companion/virtual/VirtualDeviceInternal.java
+++ b/core/java/android/companion/virtual/VirtualDeviceInternal.java
@@ -166,6 +166,20 @@
                         Binder.restoreCallingIdentity(token);
                     }
                 }
+
+                @Override
+                public void onSecureWindowHidden(int displayId) {
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        synchronized (mActivityListenersLock) {
+                            for (int i = 0; i < mActivityListeners.size(); i++) {
+                                mActivityListeners.valueAt(i).onSecureWindowHidden(displayId);
+                            }
+                        }
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
             };
 
     private final IVirtualDeviceSoundEffectListener mSoundEffectListener =
@@ -617,6 +631,10 @@
             mExecutor.execute(() ->
                     mActivityListener.onSecureWindowShown(displayId, componentName, user));
         }
+
+        public void onSecureWindowHidden(int displayId) {
+            mExecutor.execute(() -> mActivityListener.onSecureWindowHidden(displayId));
+        }
     }
 
     /**
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 6ea7834..b3f09a9 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -1288,6 +1288,17 @@
         @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API)
         default void onSecureWindowShown(int displayId, @NonNull ComponentName componentName,
                 @NonNull UserHandle user) {}
+
+        /**
+         * Called when a window with a secure surface is no longer shown on the device.
+         *
+         * @param displayId The display ID on which the window was shown before.
+         *
+         * @see Display#FLAG_SECURE
+         * @see WindowManager.LayoutParams#FLAG_SECURE
+         */
+        @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API)
+        default void onSecureWindowHidden(int displayId) {}
     }
 
     /**
diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig
index 3e6919b..46da4a3 100644
--- a/core/java/android/companion/virtual/flags.aconfig
+++ b/core/java/android/companion/virtual/flags.aconfig
@@ -81,14 +81,3 @@
   description: "Enable virtual stylus input"
   bug: "304829446"
 }
-
-flag {
-  name: "impulse_velocity_strategy_for_touch_navigation"
-  is_exported: true
-  namespace: "virtual_devices"
-  description: "Use impulse velocity strategy during conversion of touch navigation flings into Dpad events"
-  bug: "338426241"
-  metadata {
-    purpose: PURPOSE_BUGFIX
-  }
-}
\ No newline at end of file
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index cc57dc0..e271cf4 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -946,6 +946,34 @@
     }
 
     /**
+     * Make a clone of ClipData that only contains URIs. This reduces the size of data transfer over
+     * IPC and only retains important information for the purpose of verifying creator token of an
+     * Intent.
+     * @return a copy of ClipData with only URIs remained.
+     * @hide
+     */
+    public ClipData cloneOnlyUriItems() {
+        ArrayList<Item> items = null;
+        final int N = mItems.size();
+        for (int i = 0; i < N; i++) {
+            Item item = mItems.get(i);
+            if (item.getUri() != null) {
+                if (items == null) {
+                    items = new ArrayList<>(N);
+                }
+                items.add(new Item(item.getUri()));
+            } else if (item.getIntent() != null) {
+                if (items == null) {
+                    items = new ArrayList<>(N);
+                }
+                items.add(new Item(item.getIntent().cloneForCreatorToken()));
+            }
+        }
+        if (items == null || items.isEmpty()) return null;
+        return new ClipData(new ClipDescription("", new String[0]), items);
+    }
+
+    /**
      * Create a new ClipData holding data of the type
      * {@link ClipDescription#MIMETYPE_TEXT_PLAIN}.
      *
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index acad92c9..6e2ca2c 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4250,6 +4250,7 @@
             //@hide: WIFI_RTT_SERVICE,
             //@hide: ETHERNET_SERVICE,
             WIFI_RTT_RANGING_SERVICE,
+            WIFI_USD_SERVICE,
             NSD_SERVICE,
             AUDIO_SERVICE,
             AUDIO_DEVICE_VOLUME_SERVICE,
@@ -5096,6 +5097,19 @@
      */
     public static final String WIFI_RTT_RANGING_SERVICE = "wifirtt";
 
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
+     * android.net.wifi.usd.UsdManager} for Unsynchronized Service Discovery (USD) operation.
+     *
+     * @see #getSystemService(String)
+     * @see android.net.wifi.usd.UsdManager
+     * @hide
+     */
+    @FlaggedApi(android.net.wifi.flags.Flags.FLAG_USD)
+    @SystemApi
+    public static final String WIFI_USD_SERVICE = "wifi_usd";
+
     /**
      * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.net.lowpan.LowpanManager} for handling management of
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 3d2d487..d766017 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -7720,6 +7720,7 @@
     @IntDef(flag = true, prefix = { "EXTENDED_FLAG_" }, value = {
             EXTENDED_FLAG_FILTER_MISMATCH,
             EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN,
+            EXTENDED_FLAG_NESTED_INTENT_KEYS_COLLECTED,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ExtendedFlags {}
@@ -7740,6 +7741,13 @@
      */
     public static final int EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN = 1 << 1;
 
+    /**
+     * This flag indicates this intent called {@link #collectExtraIntentKeys()}.
+     *
+     * @hide
+     */
+    public static final int EXTENDED_FLAG_NESTED_INTENT_KEYS_COLLECTED = 1 << 2;
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // toUri() and parseUri() options.
@@ -7962,6 +7970,24 @@
     }
 
     /**
+     * Make a copy of all members important to identify an intent with its creator token.
+     * @hide
+     */
+    public @NonNull Intent cloneForCreatorToken() {
+        Intent clone = new Intent()
+                .setAction(this.mAction)
+                .setDataAndType(this.mData, this.mType)
+                .setPackage(this.mPackage)
+                .setComponent(this.mComponent)
+                .setFlags(this.mFlags & IMMUTABLE_FLAGS);
+        if (this.mClipData != null) {
+            clone.setClipData(this.mClipData.cloneOnlyUriItems());
+        }
+        clone.mCreatorTokenInfo = this.mCreatorTokenInfo;
+        return clone;
+    }
+
+    /**
      * Create an intent with a given action.  All other fields (data, type,
      * class) are null.  Note that the action <em>must</em> be in a
      * namespace because Intents are used globally in the system -- for
@@ -11676,7 +11702,7 @@
                 Log.w(TAG, "Failure filling in extras", e);
             }
         }
-        mCreatorTokenInfo = other.mCreatorTokenInfo;
+        fillInCreatorTokenInfo(other.mCreatorTokenInfo, changes);
         if (mayHaveCopiedUris && mContentUserHint == UserHandle.USER_CURRENT
                 && other.mContentUserHint != UserHandle.USER_CURRENT) {
             mContentUserHint = other.mContentUserHint;
@@ -11684,6 +11710,45 @@
         return changes;
     }
 
+    // keep original creator token and merge nested intent keys.
+    private void fillInCreatorTokenInfo(CreatorTokenInfo otherCreatorTokenInfo, int changes) {
+        if (otherCreatorTokenInfo != null && otherCreatorTokenInfo.mNestedIntentKeys != null) {
+            if (mCreatorTokenInfo == null) {
+                mCreatorTokenInfo = new CreatorTokenInfo();
+            }
+            ArraySet<NestedIntentKey> otherNestedIntentKeys =
+                    otherCreatorTokenInfo.mNestedIntentKeys;
+            if (mCreatorTokenInfo.mNestedIntentKeys == null) {
+                mCreatorTokenInfo.mNestedIntentKeys = new ArraySet<>(otherNestedIntentKeys);
+            } else {
+                ArraySet<NestedIntentKey> otherKeys;
+                if ((changes & FILL_IN_CLIP_DATA) == 0) {
+                    // If clip data is Not filled in from other, do not merge clip data keys.
+                    otherKeys = new ArraySet<>();
+                    int N = otherNestedIntentKeys.size();
+                    for (int i = 0; i < N; i++) {
+                        NestedIntentKey key = otherNestedIntentKeys.valueAt(i);
+                        if (key.mType != NestedIntentKey.NESTED_INTENT_KEY_TYPE_CLIP_DATA) {
+                            otherKeys.add(key);
+                        }
+                    }
+                } else {
+                    // If clip data is filled in from other, remove clip data keys from this
+                    // creatorTokenInfo and then merge every key from the others.
+                    int N = mCreatorTokenInfo.mNestedIntentKeys.size();
+                    for (int i = N - 1; i >= 0; i--) {
+                        NestedIntentKey key = mCreatorTokenInfo.mNestedIntentKeys.valueAt(i);
+                        if (key.mType == NestedIntentKey.NESTED_INTENT_KEY_TYPE_CLIP_DATA) {
+                            mCreatorTokenInfo.mNestedIntentKeys.removeAt(i);
+                        }
+                    }
+                    otherKeys = otherNestedIntentKeys;
+                }
+                mCreatorTokenInfo.mNestedIntentKeys.addAll(otherKeys);
+            }
+        }
+    }
+
     /**
      * Merge the extras data in this intent with that of other supplied intent using the
      * strategy specified using {@code extrasMerger}.
@@ -12220,6 +12285,7 @@
         private IBinder mCreatorToken;
         // Stores all extra keys whose values are intents for a top level intent.
         private ArraySet<NestedIntentKey> mNestedIntentKeys;
+
     }
 
     /**
@@ -12328,7 +12394,8 @@
     }
 
     private void collectNestedIntentKeysRecur(Set<Intent> visited) {
-        if (mExtras != null && !mExtras.isParcelled() && !mExtras.isEmpty()) {
+        addExtendedFlags(EXTENDED_FLAG_NESTED_INTENT_KEYS_COLLECTED);
+        if (mExtras != null && !mExtras.isEmpty()) {
             for (String key : mExtras.keySet()) {
                 Object value = mExtras.get(key);
 
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index b10f5e4..37f3f17 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -453,6 +453,13 @@
      * Value of {@link #colorMode} indicating that the activity should use a
      * high dynamic range if the presentation display supports it.
      *
+     * <p>Note: This does not impact SurfaceViews or SurfaceControls, as those have their own
+     * independent HDR support.</p>
+     *
+     * <p><b>Important:</b> Although this value was added in API 26, it is strongly recommended
+     * to avoid using it until API 34 which is when HDR support for the UI toolkit was officially
+     * added.</p>
+     *
      * @see android.R.attr#colorMode
      */
     public static final int COLOR_MODE_HDR = 2;
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index cccfdb0..9478422 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1449,6 +1449,97 @@
         }
     }
 
+    /**
+     * Use this to report any errors during alignment checks
+     *
+     * @hide
+     */
+    public static final int PAGE_SIZE_APP_COMPAT_FLAG_ERROR = -1;
+
+    /**
+     * Initial value for mPageSizeAppCompatFlags
+     *
+     * @hide
+     */
+    public static final int PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED = 0;
+
+    /**
+     * if set, extract libs forcefully for 16 KB device and show warning dialog.
+     *
+     * @hide
+     */
+    public static final int PAGE_SIZE_APP_COMPAT_FLAG_UNCOMPRESSED_LIBS_NOT_ALIGNED = 1 << 1;
+
+    /**
+     * if set, load 4 KB aligned ELFs on 16 KB device in compat mode and show warning dialog.
+     *
+     * @hide
+     */
+    public static final int PAGE_SIZE_APP_COMPAT_FLAG_ELF_NOT_ALIGNED = 1 << 2;
+
+    /**
+     * Run in 16 KB app compat mode. This flag will be set explicitly through settings. If set, 16
+     * KB app compat warning dialogs will still show up.
+     *
+     * @hide
+     */
+    public static final int PAGE_SIZE_APP_COMPAT_FLAG_SETTINGS_OVERRIDE_ENABLED = 1 << 3;
+
+    /**
+     * Disable 16 KB app compat mode through settings. It should only affect ELF loading as app is
+     * already installed.
+     *
+     * @hide
+     */
+    public static final int PAGE_SIZE_APP_COMPAT_FLAG_SETTINGS_OVERRIDE_DISABLED = 1 << 4;
+
+    /**
+     * Run in 16 KB app compat mode. This flag will be set explicitly through manifest. If set, hide
+     * the 16 KB app compat warning dialogs. This has the highest priority to enable compat mode.
+     *
+     * @hide
+     */
+    public static final int PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_ENABLED = 1 << 5;
+
+    /**
+     * Disable 16 KB app compat mode. This has the highest priority to disable compat mode.
+     *
+     * @hide
+     */
+    public static final int PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_DISABLED = 1 << 6;
+
+    /**
+     * Max value for page size app compat
+     *
+     * @hide
+     */
+    public static final int PAGE_SIZE_APP_COMPAT_FLAG_MAX = 1 << 7;
+
+    /**
+     * 16 KB app compat status for the app. App can have native shared libs which are not page
+     * aligned, LOAD segments inside the shared libs have to be page aligned. Apps can specify the
+     * override in manifest file as well.
+     */
+    private @PageSizeAppCompatFlags int mPageSizeAppCompatFlags =
+            ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED;
+
+    /** {@hide} */
+    @IntDef(
+            prefix = {"PAGE_SIZE_APP_COMPAT_FLAG_"},
+            value = {
+                PAGE_SIZE_APP_COMPAT_FLAG_ERROR,
+                PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED,
+                PAGE_SIZE_APP_COMPAT_FLAG_UNCOMPRESSED_LIBS_NOT_ALIGNED,
+                PAGE_SIZE_APP_COMPAT_FLAG_ELF_NOT_ALIGNED,
+                PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_ENABLED,
+                PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_DISABLED,
+                PAGE_SIZE_APP_COMPAT_FLAG_SETTINGS_OVERRIDE_ENABLED,
+                PAGE_SIZE_APP_COMPAT_FLAG_SETTINGS_OVERRIDE_DISABLED,
+                PAGE_SIZE_APP_COMPAT_FLAG_MAX,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PageSizeAppCompatFlags {}
+
     /** @hide */
     public String classLoaderName;
 
@@ -1777,7 +1868,7 @@
             pw.println(prefix + "enableOnBackInvokedCallback=" + isOnBackInvokedCallbackEnabled());
             pw.println(prefix + "allowCrossUidActivitySwitchFromBelow="
                     + allowCrossUidActivitySwitchFromBelow);
-
+            pw.println(prefix + "mPageSizeAppCompatFlags=" + mPageSizeAppCompatFlags);
         }
         pw.println(prefix + "createTimestamp=" + createTimestamp);
         if (mKnownActivityEmbeddingCerts != null) {
@@ -1897,6 +1988,10 @@
             }
             proto.write(ApplicationInfoProto.Detail.ALLOW_CROSS_UID_ACTIVITY_SWITCH_FROM_BELOW,
                     allowCrossUidActivitySwitchFromBelow);
+
+            proto.write(ApplicationInfoProto.Detail.ENABLE_PAGE_SIZE_APP_COMPAT,
+                        mPageSizeAppCompatFlags);
+
             proto.end(detailToken);
         }
         if (!ArrayUtils.isEmpty(mKnownActivityEmbeddingCerts)) {
@@ -2024,6 +2119,7 @@
         localeConfigRes = orig.localeConfigRes;
         allowCrossUidActivitySwitchFromBelow = orig.allowCrossUidActivitySwitchFromBelow;
         createTimestamp = SystemClock.uptimeMillis();
+        mPageSizeAppCompatFlags = orig.mPageSizeAppCompatFlags;
     }
 
     public String toString() {
@@ -2128,6 +2224,7 @@
         }
         dest.writeInt(localeConfigRes);
         dest.writeInt(allowCrossUidActivitySwitchFromBelow ? 1 : 0);
+        dest.writeInt(mPageSizeAppCompatFlags);
 
         sForStringSet.parcel(mKnownActivityEmbeddingCerts, dest, flags);
     }
@@ -2228,6 +2325,7 @@
         }
         localeConfigRes = source.readInt();
         allowCrossUidActivitySwitchFromBelow = source.readInt() != 0;
+        mPageSizeAppCompatFlags = source.readInt();
 
         mKnownActivityEmbeddingCerts = sForStringSet.unparcel(source);
         if (mKnownActivityEmbeddingCerts.isEmpty()) {
@@ -2765,6 +2863,11 @@
         requestRawExternalStorageAccess = value;
     }
 
+    /** {@hide} */
+    public void setPageSizeAppCompatFlags(@PageSizeAppCompatFlags int value) {
+        mPageSizeAppCompatFlags |= value;
+    }
+
     /**
      * Replaces {@link #mAppClassNamesByProcess}. This takes over the ownership of the passed map.
      * Do not modify the argument at the callsite.
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 5d4babb..9f898b8 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -848,4 +848,12 @@
     int getAppMetadataSource(String packageName, int userId);
 
     ComponentName getDomainVerificationAgent(int userId);
+
+    void setPageSizeAppCompatFlagsSettingsOverride(in String packageName, boolean enabled);
+
+    boolean isPageSizeCompatEnabled(in String packageName);
+
+    String getPageSizeCompatWarningMessage(in String packageName);
+
+    List<String> getAllApexDirectories();
 }
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 45303e6..cd62573 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -218,6 +218,17 @@
             "android.content.pm.action.CONFIRM_PRE_APPROVAL";
 
     /**
+     * Intent action to be sent to the implementer of
+     * {@link android.content.pm.dependencyinstaller.DependencyInstallerService}.
+     *
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
+    @SystemApi
+    public static final String ACTION_INSTALL_DEPENDENCY =
+            "android.content.pm.action.INSTALL_DEPENDENCY";
+
+    /**
      * An integer session ID that an operation is working with.
      *
      * @see Intent#getIntExtra(String, int)
@@ -3614,7 +3625,7 @@
          *                                      dependencies aren't already installed.
          */
         @FlaggedApi(Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
-        public void setEnableAutoInstallDependencies(boolean enableAutoInstallDependencies) {
+        public void setAutoInstallDependenciesEnabled(boolean enableAutoInstallDependencies) {
             isAutoInstallDependenciesEnabled = enableAutoInstallDependencies;
         }
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d2b43b9..a06eb1c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import static android.content.pm.SigningInfo.AppSigningSchemeVersion;
 import static android.media.audio.Flags.FLAG_FEATURE_SPATIAL_AUDIO_HEADTRACKING_LOW_LATENCY;
 
 import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES;
@@ -59,6 +60,8 @@
 import android.content.IntentSender;
 import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.dex.ArtManager;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
 import android.content.pm.verify.domain.DomainVerificationManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -94,6 +97,7 @@
 import android.telephony.ims.SipDelegateManager;
 import android.util.AndroidException;
 import android.util.Log;
+import android.util.apk.ApkSignatureVerifier;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.pm.parsing.PackageInfoCommonUtils;
@@ -804,7 +808,6 @@
         @Deprecated
         private void __metadata() {}
 
-
         //@formatter:on
         // End of generated code
 
@@ -3148,6 +3151,16 @@
     public static final long MAXIMUM_VERIFICATION_TIMEOUT = 60*60*1000;
 
     /**
+     * As the generated feature count is useful for classes that may not be compiled in the same
+     * annotation processing unit as PackageManager, we redeclare it here for visibility.
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    public static final int SDK_FEATURE_COUNT =
+            com.android.internal.pm.SystemFeaturesMetadata.SDK_FEATURE_COUNT;
+
+    /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device's
      * audio pipeline is low-latency, more suitable for audio applications sensitive to delays or
      * lag in sound input or output.
@@ -6729,6 +6742,11 @@
      * If the given permission already exists, the info you supply here
      * will be used to update it.
      *
+     * @deprecated Support for dynamic permissions is going to be removed, and apps that use dynamic
+     * permissions should declare their permissions statically inside their app manifest instead.
+     * This method will become a no-op in a future Android release and eventually be removed from
+     * the SDK.
+     *
      * @param info Description of the permission to be added.
      *
      * @return Returns true if a new permission was created, false if an
@@ -6739,7 +6757,9 @@
      *
      * @see #removePermission(String)
      */
-    //@Deprecated
+    @SuppressWarnings("HiddenAbstractMethod")
+    @FlaggedApi(android.permission.flags.Flags.FLAG_PERMISSION_TREE_APIS_DEPRECATED)
+    @Deprecated
     public abstract boolean addPermission(@NonNull PermissionInfo info);
 
     /**
@@ -6748,8 +6768,15 @@
      * allowing it to return quicker and batch a series of adds at the
      * expense of no guarantee the added permission will be retained if
      * the device is rebooted before it is written.
+     *
+     * @deprecated Support for dynamic permissions is going to be removed, and apps that use dynamic
+     * permissions should declare their permissions statically inside their app manifest instead.
+     * This method will become a no-op in a future Android release and eventually be removed from
+     * the SDK.
      */
-    //@Deprecated
+    @SuppressWarnings("HiddenAbstractMethod")
+    @FlaggedApi(android.permission.flags.Flags.FLAG_PERMISSION_TREE_APIS_DEPRECATED)
+    @Deprecated
     public abstract boolean addPermissionAsync(@NonNull PermissionInfo info);
 
     /**
@@ -6758,6 +6785,11 @@
      * -- you are only allowed to remove permissions that you are allowed
      * to add.
      *
+     * @deprecated Support for dynamic permissions is going to be removed, and apps that use dynamic
+     * permissions should declare their permissions statically inside their app manifest instead.
+     * This method will become a no-op in a future Android release and eventually be removed from
+     * the SDK.
+     *
      * @param permName The name of the permission to remove.
      *
      * @throws SecurityException if you are not allowed to remove the
@@ -6765,7 +6797,9 @@
      *
      * @see #addPermission(PermissionInfo)
      */
-    //@Deprecated
+    @SuppressWarnings("HiddenAbstractMethod")
+    @FlaggedApi(android.permission.flags.Flags.FLAG_PERMISSION_TREE_APIS_DEPRECATED)
+    @Deprecated
     public abstract void removePermission(@NonNull String permName);
 
     /**
@@ -10987,6 +11021,41 @@
     }
 
     /**
+     * Set the page compat mode override for given package
+     *
+     * @hide
+     */
+    @FlaggedApi(android.content.pm.Flags.FLAG_APP_COMPAT_OPTION_16KB)
+    public void setPageSizeAppCompatFlagsSettingsOverride(@NonNull String packageName,
+            boolean enabled) {
+        throw new UnsupportedOperationException(
+                "setPageSizeAppCompatFlagsSettingsOverride not implemented in subclass");
+    }
+
+    /**
+     * Check whether page size app compat mode is enabled for given package
+     *
+     * @hide
+     */
+    @FlaggedApi(android.content.pm.Flags.FLAG_APP_COMPAT_OPTION_16KB)
+    public boolean isPageSizeCompatEnabled(@NonNull String packageName) {
+        throw new UnsupportedOperationException(
+                "isPageSizeCompatEnabled not implemented in subclass");
+    }
+
+    /**
+     * Get the page size app compat warning dialog to show at app launch time
+     *
+     * @hide
+     */
+    @Nullable
+    @FlaggedApi(android.content.pm.Flags.FLAG_APP_COMPAT_OPTION_16KB)
+    public String getPageSizeCompatWarningMessage(@NonNull String packageName) {
+        throw new UnsupportedOperationException(
+                "getPageSizeCompatWarningMessage not implemented in subclass");
+    }
+
+     /**
      * Returns the harmful app warning string for the given app, or null if there is none set.
      *
      * @param packageName The full name of the desired package.
@@ -11932,4 +12001,31 @@
         throw new UnsupportedOperationException(
                 "parseServiceMetadata not implemented in subclass");
     }
+
+    /**
+     * Verifies and returns the
+     * <a href="https://source.android.com/docs/security/features/apksigning">app signing</a>
+     * information of the file at the given path. This operation takes a few milliseconds.
+     *
+     * Unlike {@link #getPackageArchiveInfo(String, PackageInfoFlags)} with {@link
+     * #GET_SIGNING_CERTIFICATES}, this method does not require the file to be a package archive
+     * file.
+     *
+     * @throws SigningInfoException if the verification fails
+     *
+     * @hide
+     */
+    @FlaggedApi(android.content.pm.Flags.FLAG_CLOUD_COMPILATION_PM)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static @NonNull SigningInfo getVerifiedSigningInfo(@NonNull String path,
+            @AppSigningSchemeVersion int minAppSigningSchemeVersion) throws SigningInfoException {
+        ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+        ParseResult<SigningDetails> result =
+                ApkSignatureVerifier.verify(input, path, minAppSigningSchemeVersion);
+        if (result.isError()) {
+            throw new SigningInfoException(
+                    result.getErrorCode(), result.getErrorMessage(), result.getException());
+        }
+        return new SigningInfo(result.getResult());
+    }
 }
diff --git a/core/java/android/content/pm/SigningInfo.java b/core/java/android/content/pm/SigningInfo.java
index 23daaf2..e4fbd1f 100644
--- a/core/java/android/content/pm/SigningInfo.java
+++ b/core/java/android/content/pm/SigningInfo.java
@@ -16,14 +16,20 @@
 
 package android.content.pm;
 
+import static android.content.pm.SigningDetails.SignatureSchemeVersion;
+
 import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.content.pm.SigningDetails.SignatureSchemeVersion;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.ArraySet;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.security.PublicKey;
 import java.util.Collection;
 
@@ -31,6 +37,55 @@
  * Information pertaining to the signing certificates used to sign a package.
  */
 public final class SigningInfo implements Parcelable {
+    /**
+     * JAR signing (v1 scheme).
+     * See https://source.android.com/docs/security/features/apksigning#v1.
+     *
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_CLOUD_COMPILATION_PM)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int VERSION_JAR = SignatureSchemeVersion.JAR;
+
+    /**
+     * APK signature scheme v2.
+     * See https://source.android.com/docs/security/features/apksigning/v2.
+     *
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_CLOUD_COMPILATION_PM)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int VERSION_SIGNING_BLOCK_V2 = SignatureSchemeVersion.SIGNING_BLOCK_V2;
+
+    /**
+     * APK signature scheme v3.
+     * See https://source.android.com/docs/security/features/apksigning/v3.
+     *
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_CLOUD_COMPILATION_PM)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int VERSION_SIGNING_BLOCK_V3 = SignatureSchemeVersion.SIGNING_BLOCK_V3;
+
+    /**
+     * APK signature scheme v4.
+     * See https://source.android.com/docs/security/features/apksigning/v4.
+     *
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_CLOUD_COMPILATION_PM)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int VERSION_SIGNING_BLOCK_V4 = SignatureSchemeVersion.SIGNING_BLOCK_V4;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"VERSION_"}, value = {
+            VERSION_JAR,
+            VERSION_SIGNING_BLOCK_V2,
+            VERSION_SIGNING_BLOCK_V3,
+            VERSION_SIGNING_BLOCK_V4,
+    })
+    public @interface AppSigningSchemeVersion {}
 
     @NonNull
     private final SigningDetails mSigningDetails;
@@ -198,6 +253,17 @@
         return mSigningDetails;
     }
 
+    /**
+     * Returns true if the signing certificates in this and other match exactly.
+     *
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_CLOUD_COMPILATION_PM)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public boolean signersMatchExactly(@NonNull SigningInfo other) {
+        return mSigningDetails.signaturesMatchExactly(other.mSigningDetails);
+    }
+
     public static final @android.annotation.NonNull Parcelable.Creator<SigningInfo> CREATOR =
             new Parcelable.Creator<SigningInfo>() {
         @Override
diff --git a/core/java/android/content/pm/SigningInfoException.java b/core/java/android/content/pm/SigningInfoException.java
new file mode 100644
index 0000000..a81e07e
--- /dev/null
+++ b/core/java/android/content/pm/SigningInfoException.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 android.content.pm;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+
+/**
+ * Indicates an error when verifying the
+ * <a href="https://source.android.com/docs/security/features/apksigning">app signing</a>
+ * information.
+ *
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_CLOUD_COMPILATION_PM)
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public class SigningInfoException extends Exception {
+    private final int mCode;
+
+    /** @hide */
+    public SigningInfoException(int code, @NonNull String message, @Nullable Throwable cause) {
+        super(message, cause);
+        mCode = code;
+    }
+
+    /**
+     * Returns a code representing the cause, in one of the installation parse return codes in
+     * {@link PackageManager}.
+     */
+    @FlaggedApi(Flags.FLAG_CLOUD_COMPILATION_PM)
+    public int getCode() {
+        return mCode;
+    }
+}
diff --git a/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.java b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.java
index ba089f7..35e5c44 100644
--- a/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.java
+++ b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.java
@@ -53,7 +53,14 @@
      * Callback to indicate that all the requested dependencies have been resolved and their
      * sessions created. See {@link  DependencyInstallerService#onDependenciesRequired}.
      *
+     * The system will wait for the sessions to be installed before resuming the original session
+     * which requested dependency installation.
+     *
+     * If any of the session fails to install, the system may fail the original session. The caller
+     * is expected to handle clean up of any other pending sessions remanining.
+     *
      * @param sessionIds the install session IDs for all requested dependencies
+     * @throws IllegalArgumentException if session id doesn't exist or has already failed.
      */
     public void onAllDependenciesResolved(@NonNull int[] sessionIds) {
         try {
diff --git a/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerCallback.aidl b/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerCallback.aidl
index 92d1d9e..e4cf55d 100644
--- a/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerCallback.aidl
+++ b/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerCallback.aidl
@@ -24,7 +24,7 @@
 *
 * {@hide}
 */
-oneway interface IDependencyInstallerCallback {
+interface IDependencyInstallerCallback {
     /**
      * Callback to indicate that all the requested dependencies have been resolved and have been
      * committed for installation. See {@link  DependencyInstallerService#onDependenciesRequired}.
@@ -38,4 +38,4 @@
      * and any associated sessions have been abandoned.
      */
     void onFailureToResolveAllDependencies();
-}
\ No newline at end of file
+}
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 3a01ea9..fbe581c 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -356,7 +356,7 @@
     name: "support_minor_versions_in_minsdkversion"
     namespace: "package_manager_service"
     description: "Block app installations that specify an incompatible minor SDK version"
-    bug: "377474232"
+    bug: "377302905"
 }
 
 flag {
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 813208d..d351ebc 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -341,6 +341,39 @@
   is_fixed_read_only: true
 }
 
+flag {
+    name: "cache_user_start_realtime_read_only"
+    namespace: "multiuser"
+    description: "Cache getUserStartRealtime to avoid unnecessary binder calls"
+    bug: "350416205"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+  }
+  is_fixed_read_only: true
+}
+
+flag {
+    name: "cache_user_unlock_realtime_read_only"
+    namespace: "multiuser"
+    description: "Cache getUserUnlockRealtime to avoid unnecessary binder calls"
+    bug: "350421407"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+  }
+  is_fixed_read_only: true
+}
+
+flag {
+    name: "cache_user_restrictions_read_only"
+    namespace: "multiuser"
+    description: "Cache hasUserRestriction to avoid unnecessary binder calls"
+    bug: "350419621"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+  }
+  is_fixed_read_only: true
+}
+
 # This flag guards the private space feature and all its implementations excluding the APIs. APIs are guarded by android.os.Flags.allow_private_profile.
 flag {
     name: "enable_private_space_features"
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 7254203..18a45d8d 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -595,9 +595,6 @@
                                     /*allowDuplicates=*/ true);
                             break;
                         case TAG_USES_STATIC_LIBRARY:
-                            if (!android.content.pm.Flags.sdkDependencyInstaller()) {
-                                break;
-                            }
                             String usesStaticLibName = parser.getAttributeValue(
                                     ANDROID_RES_NAMESPACE, "name");
                             long usesStaticLibVersion = parser.getAttributeIntValue(
@@ -666,7 +663,7 @@
                                     SharedLibraryInfo.TYPE_SDK_PACKAGE));
                             break;
                         case TAG_STATIC_LIBRARY:
-                            isSdkLibrary = true;
+                            isStaticLibrary = true;
                             // Mirrors ParsingPackageUtils#parseStaticLibrary until lite and full
                             // parsing are combined
                             String staticLibName = parser.getAttributeValue(
diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
index 153dd9a..e30f871 100644
--- a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
@@ -330,6 +330,36 @@
     }
 
     /**
+     * Check if a package is compatible with this platform with regards to its
+     * its minSdkVersionFull.
+     *
+     * @param minSdkVersionFullString    A string representation of a major.minor version,
+     *                                   e.g. "12.34"
+     * @param platformMinSdkVersionFull The major and minor version of the platform, i.e. the value
+     *                                  of Build.VERSION.SDK_INT_FULL
+     * @param input                     A ParseInput object to report success or failure
+     */
+    public static ParseResult<Void> verifyMinSdkVersionFull(@NonNull String minSdkVersionFullString,
+            int platformMinSdkVersionFull, @NonNull ParseInput input) {
+        int minSdkVersionFull;
+        try {
+            minSdkVersionFull = Build.parseFullVersion(minSdkVersionFullString);
+        } catch (IllegalStateException e) {
+            return input.error(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    e.getMessage());
+        }
+        if (minSdkVersionFull <= platformMinSdkVersionFull) {
+            return input.success(null);
+        }
+        return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
+                "Requires newer sdk version "
+                + Build.fullVersionToString(minSdkVersionFull)
+                + " (current version is "
+                + Build.fullVersionToString(platformMinSdkVersionFull)
+                + ")");
+    }
+
+    /**
      * Computes the targetSdkVersion to use at runtime. If the package is not compatible with this
      * platform, populates {@code outError[0]} with an error message.
      * <p>
diff --git a/core/java/android/hardware/DisplayLuts.java b/core/java/android/hardware/DisplayLuts.java
index 6343ba1..0abb30f 100644
--- a/core/java/android/hardware/DisplayLuts.java
+++ b/core/java/android/hardware/DisplayLuts.java
@@ -177,6 +177,8 @@
                     return "SAMPLING_KEY_RGB";
                 case LutProperties.SAMPLING_KEY_MAX_RGB:
                     return "SAMPLING_KEY_MAX_RGB";
+                case LutProperties.SAMPLING_KEY_CIE_Y:
+                    return "SAMPLING_KEY_CIE_Y";
                 default:
                     return "";
             }
diff --git a/core/java/android/hardware/LutProperties.java b/core/java/android/hardware/LutProperties.java
index bf40a41..abb303a 100644
--- a/core/java/android/hardware/LutProperties.java
+++ b/core/java/android/hardware/LutProperties.java
@@ -44,7 +44,8 @@
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"SAMPLING_KEY_"}, value = {
         SAMPLING_KEY_RGB,
-        SAMPLING_KEY_MAX_RGB
+        SAMPLING_KEY_MAX_RGB,
+        SAMPLING_KEY_CIE_Y
     })
     public @interface SamplingKey {
     }
@@ -57,6 +58,10 @@
     @FlaggedApi(Flags.FLAG_LUTS_API)
     public static final int SAMPLING_KEY_MAX_RGB = 1;
 
+    /** use y of CIE XYZ as the gain value of a lut */
+    @FlaggedApi(Flags.FLAG_LUTS_API)
+    public static final int SAMPLING_KEY_CIE_Y = 2;
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value = {
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index 3cf508a..58fe477 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -1066,6 +1066,7 @@
                     case ImageFormat.YUV_420_888:
                     case ImageFormat.JPEG:
                     case ImageFormat.JPEG_R:
+                    case ImageFormat.DEPTH_JPEG:
                     case ImageFormat.YCBCR_P010:
                         break;
                     default:
@@ -1096,9 +1097,10 @@
                     // processed YUV_420 buffers.
                     return getSupportedSizes(
                             extenders.second.getSupportedPostviewResolutions(sz), format);
-                }  else if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010) {
-                    // Jpeg_R/UltraHDR + YCBCR_P010 is currently not supported in the basic
-                    // extension case
+                }  else if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010 ||
+                        (Flags.depthJpegExtensions() && (format == ImageFormat.DEPTH_JPEG))) {
+                    // DepthJpeg/Jpeg_R/UltraHDR + YCBCR_P010 is currently not supported in the
+                    // basic extension case
                     return new ArrayList<>();
                 } else {
                     throw new IllegalArgumentException("Unsupported format: " + format);
@@ -1194,8 +1196,8 @@
      *
      * <p>Device-specific extensions currently support at most three
      * multi-frame capture surface formats. ImageFormat.JPEG will be supported by all
-     * extensions while ImageFormat.YUV_420_888, ImageFormat.JPEG_R, or ImageFormat.YCBCR_P010
-     * may or may not be supported.</p>
+     * extensions while ImageFormat.YUV_420_888, ImageFormat.JPEG_R, ImageFormat.YCBCR_P010 or
+     * ImageFormat.DEPTH_JPEG may or may not be supported.</p>
      *
      * @param extension the extension type
      * @param format    device-specific extension output format
@@ -1203,7 +1205,8 @@
      * supported.
      * @throws IllegalArgumentException in case of format different from ImageFormat.JPEG,
      *                                  ImageFormat.YUV_420_888, ImageFormat.JPEG_R,
-     *                                  ImageFormat.YCBCR_P010; or unsupported extension.
+     *                                  ImageFormat.DEPTH_JPEG, ImageFormat.YCBCR_P010; or
+     *                                  unsupported extension.
      */
     public @NonNull
     List<Size> getExtensionSupportedSizes(@Extension int extension, int format) {
@@ -1227,6 +1230,7 @@
                         case ImageFormat.YUV_420_888:
                         case ImageFormat.JPEG:
                         case ImageFormat.JPEG_R:
+                        case ImageFormat.DEPTH_JPEG:
                         case ImageFormat.YCBCR_P010:
                             break;
                         default:
@@ -1260,8 +1264,9 @@
                         } else {
                             return generateSupportedSizes(null, format, streamMap);
                         }
-                    } else if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010) {
-                        // Jpeg_R/UltraHDR + YCBCR_P010 is currently not supported in the
+                    } else if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010 ||
+                            (Flags.depthJpegExtensions() && (format == ImageFormat.DEPTH_JPEG))) {
+                        // DepthJpeg/Jpeg_R/UltraHDR + YCBCR_P010 is currently not supported in the
                         // basic extension case
                         return new ArrayList<>();
                     } else {
@@ -1292,7 +1297,8 @@
      * or null if no capture latency info can be provided
      * @throws IllegalArgumentException in case of format different from {@link ImageFormat#JPEG},
      *                                  {@link ImageFormat#YUV_420_888}, {@link ImageFormat#JPEG_R}
-     *                                  {@link ImageFormat#YCBCR_P010};
+     *                                  {@link ImageFormat#YCBCR_P010},
+     *                                  {@link ImageFormat#DEPTH_JPEG};
      *                                  or unsupported extension.
      */
     public @Nullable Range<Long> getEstimatedCaptureLatencyRangeMillis(@Extension int extension,
@@ -1301,6 +1307,7 @@
             case ImageFormat.YUV_420_888:
             case ImageFormat.JPEG:
             case ImageFormat.JPEG_R:
+            case ImageFormat.DEPTH_JPEG:
             case ImageFormat.YCBCR_P010:
                 //No op
                 break;
@@ -1349,8 +1356,9 @@
                     // specific and cannot be estimated accurately enough.
                     return  null;
                 }
-                if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010) {
-                    // JpegR/UltraHDR + YCBCR_P010 is not supported for basic extensions
+                if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010 ||
+                        (Flags.depthJpegExtensions() && (format == ImageFormat.DEPTH_JPEG))) {
+                    // DepthJpeg/JpegR/UltraHDR + YCBCR_P010 is not supported for basic extensions
                     return null;
                 }
 
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 266efb7..aba2345 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -1699,17 +1699,18 @@
         }
 
         if (context != null) {
-            final ActivityManager activityManager =
-                    context.getSystemService(ActivityManager.class);
-            for (ActivityManager.AppTask appTask : activityManager.getAppTasks()) {
-                final TaskInfo taskInfo = appTask.getTaskInfo();
-                final int freeformCameraCompatMode =
-                        taskInfo.appCompatTaskInfo.cameraCompatTaskInfo.freeformCameraCompatMode;
-                if (freeformCameraCompatMode != 0
-                        && taskInfo.topActivity != null
-                        && taskInfo.topActivity.getPackageName().equals(packageName)) {
-                    // WindowManager has requested rotation override.
-                    return getRotationOverrideForCompatFreeform(freeformCameraCompatMode);
+            final ActivityManager activityManager = context.getSystemService(ActivityManager.class);
+            if (activityManager != null) {
+                for (ActivityManager.AppTask appTask : activityManager.getAppTasks()) {
+                    final TaskInfo taskInfo = appTask.getTaskInfo();
+                    final int freeformCameraCompatMode = taskInfo.appCompatTaskInfo
+                            .cameraCompatTaskInfo.freeformCameraCompatMode;
+                    if (freeformCameraCompatMode != 0
+                            && taskInfo.topActivity != null
+                            && taskInfo.topActivity.getPackageName().equals(packageName)) {
+                        // WindowManager has requested rotation override.
+                        return getRotationOverrideForCompatFreeform(freeformCameraCompatMode);
+                    }
                 }
             }
         }
diff --git a/core/java/android/hardware/camera2/TotalCaptureResult.java b/core/java/android/hardware/camera2/TotalCaptureResult.java
index 7e42f43..29eaab8 100644
--- a/core/java/android/hardware/camera2/TotalCaptureResult.java
+++ b/core/java/android/hardware/camera2/TotalCaptureResult.java
@@ -86,7 +86,8 @@
         mPhysicalCaptureResults = new HashMap<String, TotalCaptureResult>();
         for (PhysicalCaptureResultInfo onePhysicalResult : physicalResults) {
             TotalCaptureResult physicalResult = new TotalCaptureResult(
-                    onePhysicalResult.getCameraId(), onePhysicalResult.getCameraMetadata(),
+                    onePhysicalResult.getCameraId(),
+                    onePhysicalResult.getCameraMetadata(),
                     parent, extras, /*partials*/null, sessionId, new PhysicalCaptureResultInfo[0]);
             mPhysicalCaptureResults.put(onePhysicalResult.getCameraId(),
                     physicalResult);
@@ -115,7 +116,8 @@
         mPhysicalCaptureResults = new HashMap<String, TotalCaptureResult>();
         for (PhysicalCaptureResultInfo onePhysicalResult : physicalResults) {
             TotalCaptureResult physicalResult = new TotalCaptureResult(
-                    onePhysicalResult.getCameraId(), onePhysicalResult.getCameraMetadata(),
+                    onePhysicalResult.getCameraId(),
+                    onePhysicalResult.getCameraMetadata(),
                     parent, requestId, frameNumber, /*partials*/null, sessionId,
                     new PhysicalCaptureResultInfo[0]);
             mPhysicalCaptureResults.put(onePhysicalResult.getCameraId(),
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index fc03b51..d511e9f 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -186,12 +186,12 @@
 
         HashMap<Integer, List<Size>> supportedCaptureSizes = new HashMap<>();
 
-        IntArray supportedCaptureOutputFormats =
-                new IntArray(CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.length);
-        supportedCaptureOutputFormats.addAll(
-                CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS);
-        supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
-        for (int format : supportedCaptureOutputFormats.toArray()) {
+        Integer[] supportedCaptureOutputFormats =
+                new Integer[CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.size()];
+        supportedCaptureOutputFormats =
+                CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.toArray(
+                        supportedCaptureOutputFormats);
+        for (int format : supportedCaptureOutputFormats) {
             List<Size> supportedSizes = extensionChars.getExtensionSupportedSizes(
                     config.getExtension(), format);
             if (supportedSizes != null) {
@@ -230,7 +230,7 @@
             Size burstCaptureSurfaceSize =
                     new Size(burstCaptureSurfaceInfo.mWidth, burstCaptureSurfaceInfo.mHeight);
             HashMap<Integer, List<Size>> supportedPostviewSizes = new HashMap<>();
-            for (int format : supportedCaptureOutputFormats.toArray()) {
+            for (int format : supportedCaptureOutputFormats) {
                 List<Size> supportedSizesPostview = extensionChars.getPostviewSupportedSizes(
                         config.getExtension(), burstCaptureSurfaceSize, format);
                 if (supportedSizesPostview != null) {
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index ea70abb..34c0f7b 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -34,6 +34,7 @@
 import android.hardware.camera2.CameraExtensionCharacteristics;
 import android.hardware.camera2.CameraManager;
 import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CameraMetadataInfo;
 import android.hardware.camera2.CameraOfflineSession;
 import android.hardware.camera2.CaptureFailure;
 import android.hardware.camera2.CaptureRequest;
@@ -59,6 +60,8 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.os.SystemClock;
@@ -129,6 +132,8 @@
     final Object mInterfaceLock = new Object(); // access from this class and Session only!
     private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
 
+    private long mFMQReader; // native fmq reader ptr
+
     private final StateCallback mDeviceCallback;
     private volatile StateCallbackKK mSessionStateCallback;
     private final Executor mDeviceExecutor;
@@ -476,6 +481,9 @@
             if (mInError) return;
 
             mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice);
+            Parcel resultParcel = Parcel.obtain();
+            mRemoteDevice.getCaptureResultMetadataQueue().writeToParcel(resultParcel, 0);
+            mFMQReader = nativeCreateFMQReader(resultParcel);
 
             IBinder remoteDeviceBinder = remoteDevice.asBinder();
             // For legacy camera device, remoteDevice is in the same process, and
@@ -1682,6 +1690,7 @@
             if (mRemoteDevice != null || mInError) {
                 mDeviceExecutor.execute(mCallOnClosed);
             }
+            nativeClose(mFMQReader);
 
             mRemoteDevice = null;
         }
@@ -2416,27 +2425,61 @@
                 }
             }
         }
+        private PhysicalCaptureResultInfo[] readMetadata(
+            PhysicalCaptureResultInfo[] srcPhysicalResults) {
+            PhysicalCaptureResultInfo[] retVal =
+                    new PhysicalCaptureResultInfo[srcPhysicalResults.length];
+            int i = 0;
+            long fmqSize = 0;
+            for (PhysicalCaptureResultInfo srcPhysicalResult : srcPhysicalResults) {
+                CameraMetadataNative physicalCameraMetadata = null;
+                if (srcPhysicalResult.getCameraMetadataInfo().getTag() ==
+                        CameraMetadataInfo.fmqSize) {
+                    fmqSize = srcPhysicalResult.getCameraMetadataInfo().getFmqSize();
+                    physicalCameraMetadata =
+                            new CameraMetadataNative(nativeReadResultMetadata(mFMQReader, fmqSize));
+                } else {
+                    physicalCameraMetadata = srcPhysicalResult.getCameraMetadata();
+                }
+                PhysicalCaptureResultInfo physicalResultInfo =
+                        new PhysicalCaptureResultInfo(
+                                srcPhysicalResult.getCameraId(), physicalCameraMetadata);
+                retVal[i] = physicalResultInfo;
+                i++;
+            }
+           return retVal;
+        }
 
         @Override
-        public void onResultReceived(CameraMetadataNative result,
+        public void onResultReceived(CameraMetadataInfo resultInfo,
                 CaptureResultExtras resultExtras, PhysicalCaptureResultInfo physicalResults[])
                 throws RemoteException {
             int requestId = resultExtras.getRequestId();
             long frameNumber = resultExtras.getFrameNumber();
-
-            if (DEBUG) {
-                Log.v(TAG, "Received result frame " + frameNumber + " for id "
-                        + requestId);
-            }
-
             synchronized(mInterfaceLock) {
                 if (mRemoteDevice == null) return; // Camera already closed
-
+                PhysicalCaptureResultInfo savedPhysicalResults[] = physicalResults;
+                CameraMetadataNative result;
+                if (resultInfo.getTag() == CameraMetadataInfo.fmqSize) {
+                    CameraMetadataNative fmqMetadata =
+                            new CameraMetadataNative(
+                                    nativeReadResultMetadata(mFMQReader, resultInfo.getFmqSize()));
+                    result = fmqMetadata;
+                } else {
+                    result = resultInfo.getMetadata();
+                }
+                physicalResults = readMetadata(savedPhysicalResults);
+                if (DEBUG) {
+                    Log.v(TAG, "Received result frame " + frameNumber + " for id "
+                            + requestId);
+                }
 
                 // Redirect device callback to the offline session in case we are in the middle
                 // of an offline switch
                 if (mOfflineSessionImpl != null) {
-                    mOfflineSessionImpl.getCallbacks().onResultReceived(result, resultExtras,
+                    CameraMetadataInfo resultInfoOffline = CameraMetadataInfo.metadata(result);
+                    mOfflineSessionImpl.getCallbacks().onResultReceived(resultInfoOffline,
+                            resultExtras,
                             physicalResults);
                     return;
                 }
@@ -2824,6 +2867,11 @@
         }
     }
 
+    private static native long nativeCreateFMQReader(Parcel resultQueue);
+    //TODO: Investigate adding FastNative b/62791857
+    private static native long nativeReadResultMetadata(long ptr, long metadataSize);
+    private static native void nativeClose(long ptr);
+
     @Override
     public @CAMERA_AUDIO_RESTRICTION int getCameraAudioRestriction() throws CameraAccessException {
         synchronized(mInterfaceLock) {
@@ -2870,4 +2918,4 @@
             }
         }
     }
-}
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index ce1609d..ed73e62 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -186,12 +186,12 @@
         }
 
         HashMap<Integer, List<Size>> supportedCaptureSizes = new HashMap<>();
-        IntArray supportedCaptureOutputFormats =
-                new IntArray(CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.length);
-        supportedCaptureOutputFormats.addAll(
-                CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS);
-        supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
-        for (int format : supportedCaptureOutputFormats.toArray()) {
+        Integer[] supportedCaptureOutputFormats =
+                new Integer[CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.size()];
+        supportedCaptureOutputFormats =
+                CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.toArray(
+                        supportedCaptureOutputFormats);
+        for (int format : supportedCaptureOutputFormats) {
             List<Size> supportedSizes = extensionChars.getExtensionSupportedSizes(
                     config.getExtension(), format);
             if (supportedSizes != null) {
@@ -223,7 +223,7 @@
             Size burstCaptureSurfaceSize =
                     new Size(burstCaptureSurfaceInfo.mWidth, burstCaptureSurfaceInfo.mHeight);
             HashMap<Integer, List<Size>> supportedPostviewSizes = new HashMap<>();
-            for (int format : supportedCaptureOutputFormats.toArray()) {
+            for (int format : supportedCaptureOutputFormats) {
                 List<Size> supportedSizesPostview = extensionChars.getPostviewSupportedSizes(
                         config.getExtension(), burstCaptureSurfaceSize, format);
                 if (supportedSizesPostview != null) {
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
index f91d277..212c909 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
@@ -32,11 +32,14 @@
 import android.util.IntArray;
 import android.util.Log;
 import android.util.Size;
+import android.util.SparseIntArray;
 import android.view.Surface;
 
 import com.android.internal.camera.flags.Flags;
 
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Executor;
@@ -48,11 +51,16 @@
     public final static int JPEG_DEFAULT_QUALITY = 100;
     public final static int JPEG_DEFAULT_ROTATION = 0;
 
-    public static final int[] SUPPORTED_CAPTURE_OUTPUT_FORMATS = {
-            CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT,
-            ImageFormat.JPEG,
-            ImageFormat.JPEG_R
-    };
+    public static HashSet<Integer> SUPPORTED_CAPTURE_OUTPUT_FORMATS = new HashSet<>();
+
+    static {
+        SUPPORTED_CAPTURE_OUTPUT_FORMATS.addAll(Arrays.asList(
+                CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT, ImageFormat.JPEG,
+                ImageFormat.YCBCR_P010, ImageFormat.JPEG_R ));
+        if (Flags.depthJpegExtensions()) {
+            SUPPORTED_CAPTURE_OUTPUT_FORMATS.add(ImageFormat.DEPTH_JPEG);
+        }
+    }
 
     public static class SurfaceInfo {
         public int mWidth = 0;
@@ -101,6 +109,13 @@
             surfaceInfo.mFormat = ImageFormat.JPEG_R;
             return surfaceInfo;
         }
+        if (Flags.depthJpegExtensions()) {
+            if ((nativeFormat == StreamConfigurationMap.HAL_PIXEL_FORMAT_BLOB)
+                    && (dataspace == StreamConfigurationMap.HAL_DATASPACE_DYNAMIC_DEPTH)) {
+                surfaceInfo.mFormat = ImageFormat.DEPTH_JPEG;
+                return surfaceInfo;
+            }
+        }
 
         return surfaceInfo;
     }
@@ -125,14 +140,14 @@
     public static Surface getBurstCaptureSurface(
             @NonNull List<OutputConfiguration> outputConfigs,
             @NonNull HashMap<Integer, List<Size>> supportedCaptureSizes) {
-        IntArray supportedCaptureOutputFormats =
-                new IntArray(CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.length);
-        supportedCaptureOutputFormats.addAll(
-                CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS);
-        supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
+        Integer[] supportedCaptureOutputFormats =
+                new Integer[CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.size()];
+        supportedCaptureOutputFormats =
+                CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.toArray(
+                        supportedCaptureOutputFormats);
         for (OutputConfiguration config : outputConfigs) {
             SurfaceInfo surfaceInfo = querySurface(config.getSurface());
-            for (int supportedFormat : supportedCaptureOutputFormats.toArray()) {
+            for (int supportedFormat : supportedCaptureOutputFormats) {
                 if (surfaceInfo.mFormat == supportedFormat) {
                     Size captureSize = new Size(surfaceInfo.mWidth, surfaceInfo.mHeight);
                     if (supportedCaptureSizes.containsKey(supportedFormat)) {
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index c0a5928..d7b6f11 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -391,6 +391,18 @@
     }
 
     /**
+     * Take ownership of native metadata
+     */
+    public CameraMetadataNative(long metadataPtr) {
+        super();
+        mMetadataPtr = metadataPtr;
+        if (mMetadataPtr == 0) {
+            throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
+        }
+        updateNativeAllocation();
+    }
+
+    /**
      * Move the contents from {@code other} into a new camera metadata instance.</p>
      *
      * <p>After this call, {@code other} will become empty.</p>
diff --git a/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java
index 1769c46..e660d6a 100644
--- a/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java
@@ -28,6 +28,7 @@
 import android.hardware.camera2.CaptureFailure;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.CameraMetadataInfo;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraOfflineSession;
 import android.hardware.camera2.TotalCaptureResult;
@@ -291,10 +292,10 @@
         }
 
         @Override
-        public void onResultReceived(CameraMetadataNative result,
+        public void onResultReceived(CameraMetadataInfo resultInfo,
                 CaptureResultExtras resultExtras, PhysicalCaptureResultInfo physicalResults[])
                 throws RemoteException {
-
+            CameraMetadataNative result = resultInfo.getMetadata();
             int requestId = resultExtras.getRequestId();
             long frameNumber = resultExtras.getFrameNumber();
 
diff --git a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
index 831c75ec..a79e084 100644
--- a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
+++ b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
@@ -26,6 +26,7 @@
 import android.hardware.camera2.params.SessionConfiguration;
 import android.hardware.camera2.utils.ExceptionUtils;
 import android.hardware.camera2.utils.SubmitInfo;
+import android.hardware.common.fmq.MQDescriptor;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
@@ -313,4 +314,15 @@
             throw ExceptionUtils.throwAsPublicException(e);
         }
     }
-}
+
+    public MQDescriptor<Byte, Byte> getCaptureResultMetadataQueue() throws CameraAccessException {
+        try {
+            return mRemoteDevice.getCaptureResultMetadataQueue();
+        } catch (ServiceSpecificException e) {
+            throw ExceptionUtils.throwAsPublicException(e);
+        } catch (RemoteException e) {
+            throw ExceptionUtils.throwAsPublicException(e);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/camera2/impl/PhysicalCaptureResultInfo.java b/core/java/android/hardware/camera2/impl/PhysicalCaptureResultInfo.java
index 09619d0..77296d1 100644
--- a/core/java/android/hardware/camera2/impl/PhysicalCaptureResultInfo.java
+++ b/core/java/android/hardware/camera2/impl/PhysicalCaptureResultInfo.java
@@ -15,6 +15,7 @@
  */
 package android.hardware.camera2.impl;
 
+import android.hardware.camera2.CameraMetadataInfo;
 import android.hardware.camera2.impl.CameraMetadataNative;
 
 import android.os.Parcel;
@@ -25,7 +26,7 @@
  */
 public class PhysicalCaptureResultInfo implements Parcelable {
     private String cameraId;
-    private CameraMetadataNative cameraMetadata;
+    private CameraMetadataInfo cameraMetadataInfo;
 
     public static final @android.annotation.NonNull Parcelable.Creator<PhysicalCaptureResultInfo> CREATOR =
             new Parcelable.Creator<PhysicalCaptureResultInfo>() {
@@ -46,7 +47,7 @@
 
     public PhysicalCaptureResultInfo(String cameraId, CameraMetadataNative cameraMetadata) {
         this.cameraId = cameraId;
-        this.cameraMetadata = cameraMetadata;
+        this.cameraMetadataInfo = CameraMetadataInfo.metadata(cameraMetadata);
     }
 
     @Override
@@ -57,13 +58,12 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(cameraId);
-        cameraMetadata.writeToParcel(dest, flags);
+        cameraMetadataInfo.writeToParcel(dest, flags);
     }
 
     public void readFromParcel(Parcel in) {
         cameraId = in.readString();
-        cameraMetadata = new CameraMetadataNative();
-        cameraMetadata.readFromParcel(in);
+        cameraMetadataInfo = CameraMetadataInfo.CREATOR.createFromParcel(in);
     }
 
     public String getCameraId() {
@@ -71,6 +71,11 @@
     }
 
     public CameraMetadataNative getCameraMetadata() {
-        return cameraMetadata;
+        return cameraMetadataInfo.getMetadata();
     }
-}
+
+    public CameraMetadataInfo getCameraMetadataInfo() {
+        return cameraMetadataInfo;
+    }
+
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/contexthub/HubEndpoint.java b/core/java/android/hardware/contexthub/HubEndpoint.java
index 078b4d4..7efdd6d 100644
--- a/core/java/android/hardware/contexthub/HubEndpoint.java
+++ b/core/java/android/hardware/contexthub/HubEndpoint.java
@@ -18,6 +18,7 @@
 
 import android.annotation.CallbackExecutor;
 import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -31,6 +32,8 @@
 
 import androidx.annotation.GuardedBy;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -48,6 +51,46 @@
 public class HubEndpoint {
     private static final String TAG = "HubEndpoint";
 
+    /**
+     * Constants describing the outcome of operations through HubEndpoints (like opening/closing of
+     * sessions or stopping of endpoints).
+     *
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(
+            prefix = {"REASON_"},
+            value = {
+                REASON_FAILURE,
+                REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED,
+                REASON_CLOSE_ENDPOINT_SESSION_REQUESTED,
+                REASON_ENDPOINT_INVALID,
+                REASON_ENDPOINT_STOPPED,
+            })
+    public @interface Reason {}
+
+    /** Unclassified failure */
+    public static final int REASON_FAILURE = 0;
+
+    // The values 1 and 2 are reserved at the Context Hub HAL but not exposed to apps.
+
+    /** The peer rejected the request to open this endpoint session. */
+    public static final int REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED = 3;
+
+    /** The peer closed this endpoint session. */
+    public static final int REASON_CLOSE_ENDPOINT_SESSION_REQUESTED = 4;
+
+    /** The peer endpoint is invalid. */
+    public static final int REASON_ENDPOINT_INVALID = 5;
+
+    /**
+     * The endpoint is now stopped. The app should retrieve the endpoint info using {@link
+     * android.hardware.location.ContextHubManager#findEndpoints} or register updates through
+     * {@link android.hardware.location.ContextHubManager#registerEndpointDiscoveryCallback}
+     * to get notified if the endpoint restarts.
+     */
+    public static final int REASON_ENDPOINT_STOPPED = 6;
+
     private final Object mLock = new Object();
     private final HubEndpointInfo mPendingHubEndpointInfo;
     @Nullable private final IHubEndpointLifecycleCallback mLifecycleCallback;
@@ -173,9 +216,7 @@
 
                     try {
                         mServiceToken.closeSession(
-                                sessionId,
-                                IHubEndpointLifecycleCallback
-                                        .REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED);
+                                sessionId, REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED);
                     } catch (RemoteException e) {
                         e.rethrowFromSystemServer();
                     }
@@ -396,9 +437,7 @@
 
         try {
             // Oneway notification to system service
-            serviceToken.closeSession(
-                    session.getId(),
-                    IHubEndpointLifecycleCallback.REASON_CLOSE_ENDPOINT_SESSION_REQUESTED);
+            serviceToken.closeSession(session.getId(), REASON_CLOSE_ENDPOINT_SESSION_REQUESTED);
         } catch (RemoteException e) {
             Log.e(TAG, "closeSession: failed to close session " + session, e);
             e.rethrowFromSystemServer();
diff --git a/core/java/android/hardware/contexthub/HubServiceInfo.java b/core/java/android/hardware/contexthub/HubServiceInfo.java
index c7fe77c..a1c52fb 100644
--- a/core/java/android/hardware/contexthub/HubServiceInfo.java
+++ b/core/java/android/hardware/contexthub/HubServiceInfo.java
@@ -17,12 +17,10 @@
 
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
-import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.chre.flags.Flags;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.ParcelableHolder;
 
 import androidx.annotation.NonNull;
 
@@ -76,15 +74,12 @@
     private final int mMajorVersion;
     private final int mMinorVersion;
 
-    @NonNull private final ParcelableHolder mExtendedInfo;
-
     /** @hide */
     public HubServiceInfo(android.hardware.contexthub.Service service) {
         mServiceDescriptor = service.serviceDescriptor;
         mFormat = service.format;
         mMajorVersion = service.majorVersion;
         mMinorVersion = service.minorVersion;
-        mExtendedInfo = service.extendedInfo;
     }
 
     private HubServiceInfo(Parcel in) {
@@ -92,20 +87,17 @@
         mFormat = in.readInt();
         mMajorVersion = in.readInt();
         mMinorVersion = in.readInt();
-        mExtendedInfo = ParcelableHolder.CREATOR.createFromParcel(in);
     }
 
     public HubServiceInfo(
             @NonNull String serviceDescriptor,
             @ServiceFormat int format,
             int majorVersion,
-            int minorVersion,
-            @NonNull ParcelableHolder extendedInfo) {
+            int minorVersion) {
         mServiceDescriptor = serviceDescriptor;
         mFormat = format;
         mMajorVersion = majorVersion;
         mMinorVersion = minorVersion;
-        mExtendedInfo = extendedInfo;
     }
 
     /** Get the unique identifier of this service. See {@link Builder} for more information. */
@@ -134,17 +126,10 @@
         return mMinorVersion;
     }
 
-    /** Get the {@link ParcelableHolder} for the extended information about the service. */
-    @NonNull
-    public ParcelableHolder getExtendedInfo() {
-        return mExtendedInfo;
-    }
-
     /** Parcel implementation details */
     @Override
     public int describeContents() {
-        // Passthrough describeContents flags for mExtendedInfo because we don't have FD otherwise.
-        return mExtendedInfo.describeContents();
+        return 0;
     }
 
     /** Parcel implementation details */
@@ -154,7 +139,6 @@
         dest.writeInt(mFormat);
         dest.writeInt(mMajorVersion);
         dest.writeInt(mMinorVersion);
-        mExtendedInfo.writeToParcel(dest, flags);
     }
 
     /** Builder for a {@link HubServiceInfo} object. */
@@ -165,9 +149,6 @@
         private final int mMajorVersion;
         private final int mMinorVersion;
 
-        private final ParcelableHolder mExtendedInfo =
-                new ParcelableHolder(Parcelable.PARCELABLE_STABILITY_VINTF);
-
         /**
          * Create a builder for {@link HubServiceInfo} with a service descriptor.
          *
@@ -220,20 +201,6 @@
         }
 
         /**
-         * Set the extended information of this service.
-         *
-         * @param extendedInfo Parcelable with extended information about this service. The
-         *     parcelable needs to have at least VINTF stability. Null can be used to clear a
-         *     previously set value.
-         * @throws android.os.BadParcelableException if the parcelable cannot be used.
-         */
-        @NonNull
-        public Builder setExtendedInfo(@Nullable Parcelable extendedInfo) {
-            mExtendedInfo.setParcelable(extendedInfo);
-            return this;
-        }
-
-        /**
          * Build the {@link HubServiceInfo} object.
          *
          * @throws IllegalStateException if the Builder is missing required info.
@@ -244,7 +211,7 @@
                 throw new IllegalStateException("Major and minor version must be set.");
             }
             return new HubServiceInfo(
-                    mServiceDescriptor, mFormat, mMajorVersion, mMinorVersion, mExtendedInfo);
+                    mServiceDescriptor, mFormat, mMajorVersion, mMinorVersion);
         }
     }
 
diff --git a/core/java/android/hardware/contexthub/IContextHubEndpointDiscoveryCallback.aidl b/core/java/android/hardware/contexthub/IContextHubEndpointDiscoveryCallback.aidl
new file mode 100644
index 0000000..245be93
--- /dev/null
+++ b/core/java/android/hardware/contexthub/IContextHubEndpointDiscoveryCallback.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright 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.hardware.contexthub;
+
+import android.hardware.contexthub.HubEndpointInfo;
+
+/**
+ * @hide
+ */
+oneway interface IContextHubEndpointDiscoveryCallback {
+    /**
+     * Called when endpoint(s) start.
+     * @param hubEndpointInfoList The list of endpoints that started.
+     */
+    void onEndpointsStarted(in HubEndpointInfo[] hubEndpointInfoList);
+
+    /**
+     * Called when endpoint(s) stopped.
+     * @param hubEndpointInfoList The list of endpoints that started.
+     * @param reason The reason why the endpoints stopped.
+     */
+    void onEndpointsStopped(in HubEndpointInfo[] hubEndpointInfoList, int reason);
+}
diff --git a/core/java/android/hardware/contexthub/IHubEndpointDiscoveryCallback.java b/core/java/android/hardware/contexthub/IHubEndpointDiscoveryCallback.java
new file mode 100644
index 0000000..a61a7eb
--- /dev/null
+++ b/core/java/android/hardware/contexthub/IHubEndpointDiscoveryCallback.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 android.hardware.contexthub;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.chre.flags.Flags;
+
+import java.util.List;
+
+/**
+ * Interface for listening to updates about endpoint availability.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public interface IHubEndpointDiscoveryCallback {
+    /**
+     * Called when a list of hub endpoints have started.
+     *
+     * @param discoveryInfoList The list containing hub discovery information.
+     */
+    void onEndpointsStarted(@NonNull List<HubDiscoveryInfo> discoveryInfoList);
+
+    /**
+     * Called when a list of hub endpoints have stopped.
+     *
+     * @param discoveryInfoList The list containing hub discovery information.
+     * @param reason The reason the endpoints stopped.
+     */
+    void onEndpointsStopped(
+            @NonNull List<HubDiscoveryInfo> discoveryInfoList, @HubEndpoint.Reason int reason);
+}
diff --git a/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java b/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java
index 4688439..fe449bb 100644
--- a/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java
+++ b/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java
@@ -17,15 +17,11 @@
 package android.hardware.contexthub;
 
 import android.annotation.FlaggedApi;
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.chre.flags.Flags;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
 /**
  * Interface for listening to lifecycle events of a hub endpoint.
  *
@@ -34,24 +30,6 @@
 @SystemApi
 @FlaggedApi(Flags.FLAG_OFFLOAD_API)
 public interface IHubEndpointLifecycleCallback {
-    /** Unknown reason. */
-    int REASON_UNSPECIFIED = 0;
-
-    /** The peer rejected the request to open this endpoint session. */
-    int REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED = 3;
-
-    /** The peer closed this endpoint session. */
-    int REASON_CLOSE_ENDPOINT_SESSION_REQUESTED = 4;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({
-        REASON_UNSPECIFIED,
-        REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED,
-        REASON_CLOSE_ENDPOINT_SESSION_REQUESTED,
-    })
-    @interface EndpointLifecycleReason {}
-
     /**
      * Called when an endpoint is requesting a session be opened with another endpoint.
      *
@@ -78,5 +56,5 @@
      *     used.
      * @param reason The reason why this session was closed.
      */
-    void onSessionClosed(@NonNull HubEndpointSession session, @EndpointLifecycleReason int reason);
+    void onSessionClosed(@NonNull HubEndpointSession session, @HubEndpoint.Reason int reason);
 }
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 1e66bee..a31b87f 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -1507,13 +1507,6 @@
                 mExecutor.execute(mCallback::onStopped);
             }
         }
-
-        @Override // Binder call
-        public void onRequestedBrightnessChanged(float brightness) {
-            if (mCallback != null) {
-                mExecutor.execute(() -> mCallback.onRequestedBrightnessChanged(brightness));
-            }
-        }
     }
 
     /**
diff --git a/core/java/android/hardware/display/IBrightnessListener.aidl b/core/java/android/hardware/display/IBrightnessListener.aidl
new file mode 100644
index 0000000..f5d3743
--- /dev/null
+++ b/core/java/android/hardware/display/IBrightnessListener.aidl
@@ -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 android.hardware.display;
+
+/**
+ * Interface for notifying the display owner about brightness changes.
+ *
+ * @hide
+ */
+oneway interface IBrightnessListener {
+    /**
+     * Called when the display's brightness has changed.
+     *
+     * @param brightness the new brightness of the display. Value of {@code 0.0} indicates the
+     *   minimum supported brightness and value of {@code 1.0} indicates the maximum supported
+     *   brightness.
+     */
+    void onBrightnessChanged(float brightness);
+}
diff --git a/core/java/android/hardware/display/IVirtualDisplayCallback.aidl b/core/java/android/hardware/display/IVirtualDisplayCallback.aidl
index 9cc0364..c3490d1 100644
--- a/core/java/android/hardware/display/IVirtualDisplayCallback.aidl
+++ b/core/java/android/hardware/display/IVirtualDisplayCallback.aidl
@@ -38,9 +38,4 @@
      * of the application to release() the virtual display.
      */
     void onStopped();
-
-    /**
-     * Called when the virtual display's requested brightness has changed.
-     */
-    void onRequestedBrightnessChanged(float brightness);
 }
diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java
index 3b573ea..32b6405 100644
--- a/core/java/android/hardware/display/VirtualDisplay.java
+++ b/core/java/android/hardware/display/VirtualDisplay.java
@@ -16,8 +16,6 @@
 package android.hardware.display;
 
 import android.annotation.FlaggedApi;
-import android.annotation.FloatRange;
-import android.annotation.SystemApi;
 import android.view.Display;
 import android.view.Surface;
 
@@ -166,25 +164,5 @@
          * of the application to release() the virtual display.
          */
         public void onStopped() { }
-
-        /**
-         * Called when the requested brightness of the display has changed.
-         *
-         * <p>The system may adjust the display's brightness based on user or app activity. This
-         * callback will only be invoked if the display has an explicitly specified default
-         * brightness value.</p>
-         *
-         * <p>Value of {@code 0.0} indicates the minimum supported brightness and value of
-         * {@code 1.0} indicates the maximum supported brightness.</p>
-         *
-         * @see android.view.View#setKeepScreenOn(boolean)
-         * @see android.view.WindowManager.LayoutParams#screenBrightness
-         * @see VirtualDisplayConfig.Builder#setDefaultBrightness(float)
-         * @hide
-         */
-        @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER)
-        @SystemApi
-        public void onRequestedBrightnessChanged(
-                @FloatRange(from = 0.0f, to = 1.0f) float brightness) {}
     }
 }
diff --git a/core/java/android/hardware/display/VirtualDisplayConfig.java b/core/java/android/hardware/display/VirtualDisplayConfig.java
index 57d9d28..eceaa8f 100644
--- a/core/java/android/hardware/display/VirtualDisplayConfig.java
+++ b/core/java/android/hardware/display/VirtualDisplayConfig.java
@@ -18,11 +18,13 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.FlaggedApi;
 import android.annotation.FloatRange;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.hardware.display.DisplayManager.VirtualDisplayFlag;
 import android.media.projection.MediaProjection;
@@ -38,6 +40,7 @@
 import java.util.Collections;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.Executor;
 
 /**
  * Holds configuration used to create {@link VirtualDisplay} instances.
@@ -63,6 +66,7 @@
     private final DisplayCutout mDisplayCutout;
     private final boolean mIgnoreActivitySizeRestrictions;
     private final float mDefaultBrightness;
+    private final IBrightnessListener mBrightnessListener;
 
     private VirtualDisplayConfig(
             @NonNull String name,
@@ -79,7 +83,8 @@
             boolean isHomeSupported,
             @Nullable DisplayCutout displayCutout,
             boolean ignoreActivitySizeRestrictions,
-            @FloatRange(from = 0.0f, to = 1.0f) float defaultBrightness) {
+            @FloatRange(from = 0.0f, to = 1.0f) float defaultBrightness,
+            IBrightnessListener brightnessListener) {
         mName = name;
         mWidth = width;
         mHeight = height;
@@ -95,6 +100,7 @@
         mDisplayCutout = displayCutout;
         mIgnoreActivitySizeRestrictions = ignoreActivitySizeRestrictions;
         mDefaultBrightness = defaultBrightness;
+        mBrightnessListener = brightnessListener;
     }
 
     /**
@@ -167,14 +173,20 @@
      * indicates the maximum supported brightness.</p>
      *
      * @see Builder#setDefaultBrightness(float)
-     * @hide
      */
     @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER)
-    @SystemApi
     public @FloatRange(from = 0.0f, to = 1.0f) float getDefaultBrightness() {
         return mDefaultBrightness;
     }
 
+    /**
+     * Returns the listener to get notified about changes in the display brightness.
+     * @hide
+     */
+    @Nullable
+    public IBrightnessListener getBrightnessListener() {
+        return mBrightnessListener;
+    }
 
     /**
      * Returns the unique identifier for the display. Shouldn't be displayed to the user.
@@ -266,6 +278,7 @@
         DisplayCutout.ParcelableWrapper.writeCutoutToParcel(mDisplayCutout, dest, flags);
         dest.writeBoolean(mIgnoreActivitySizeRestrictions);
         dest.writeFloat(mDefaultBrightness);
+        dest.writeStrongBinder(mBrightnessListener != null ? mBrightnessListener.asBinder() : null);
     }
 
     @Override
@@ -294,7 +307,9 @@
                 && mIsHomeSupported == that.mIsHomeSupported
                 && mIgnoreActivitySizeRestrictions == that.mIgnoreActivitySizeRestrictions
                 && Objects.equals(mDisplayCutout, that.mDisplayCutout)
-                && mDefaultBrightness == that.mDefaultBrightness;
+                && mDefaultBrightness == that.mDefaultBrightness
+                && Objects.equals(mBrightnessListener, that.mBrightnessListener);
+
     }
 
     @Override
@@ -303,7 +318,7 @@
                 mName, mWidth, mHeight, mDensityDpi, mFlags, mSurface, mUniqueId,
                 mDisplayIdToMirror, mWindowManagerMirroringEnabled, mDisplayCategories,
                 mRequestedRefreshRate, mIsHomeSupported, mDisplayCutout,
-                mIgnoreActivitySizeRestrictions, mDefaultBrightness);
+                mIgnoreActivitySizeRestrictions, mDefaultBrightness, mBrightnessListener);
         return hashCode;
     }
 
@@ -345,6 +360,43 @@
         mDisplayCutout = DisplayCutout.ParcelableWrapper.readCutoutFromParcel(in);
         mIgnoreActivitySizeRestrictions = in.readBoolean();
         mDefaultBrightness = in.readFloat();
+        mBrightnessListener = IBrightnessListener.Stub.asInterface(in.readStrongBinder());
+
+    }
+
+    /**
+     * Listener for display brightness changes.
+     */
+    @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER)
+    public interface BrightnessListener {
+
+        /**
+         * Called when the display's brightness has changed.
+         *
+         * @param brightness the new brightness of the display. Value of {@code 0.0} indicates the
+         *   minimum supported brightness and value of {@code 1.0} indicates the maximum supported
+         *   brightness.
+         */
+        void onBrightnessChanged(@FloatRange(from = 0.0f, to = 1.0f) float brightness);
+    }
+
+    private static class BrightnessListenerDelegate extends IBrightnessListener.Stub {
+
+        @NonNull
+        private final Executor mExecutor;
+        @NonNull
+        private final BrightnessListener mListener;
+
+        BrightnessListenerDelegate(@NonNull @CallbackExecutor Executor executor,
+                @NonNull BrightnessListener listener) {
+            mExecutor = executor;
+            mListener = listener;
+        }
+
+        @Override
+        public void onBrightnessChanged(float brightness) {
+            mExecutor.execute(() -> mListener.onBrightnessChanged(brightness));
+        }
     }
 
     @NonNull
@@ -380,6 +432,7 @@
         private DisplayCutout mDisplayCutout = null;
         private boolean mIgnoreActivitySizeRestrictions = false;
         private float mDefaultBrightness = 0.0f;
+        private IBrightnessListener mBrightnessListener = null;
 
         /**
          * Creates a new Builder.
@@ -575,7 +628,7 @@
          * Sets the default brightness of the display.
          *
          * <p>The system will use this brightness value whenever the display should be bright, i.e.
-         * it is powered on and not dimmed due to user activity or app activity.</p>
+         * it is powered on and not modified due to user activity or app activity.</p>
          *
          * <p>Value of {@code 0.0} indicates the minimum supported brightness and value of
          * {@code 1.0} indicates the maximum supported brightness.</p>
@@ -583,12 +636,9 @@
          * <p>If unset, defaults to {@code 0.0}</p>
          *
          * @see android.view.View#setKeepScreenOn(boolean)
-         * @see Builder#setDefaultBrightness(float)
-         * @see VirtualDisplay.Callback#onRequestedBrightnessChanged(float)
-         * @hide
+         * @see #setBrightnessListener(Executor, BrightnessListener)
          */
         @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER)
-        @SystemApi
         @NonNull
         public Builder setDefaultBrightness(@FloatRange(from = 0.0f, to = 1.0f) float brightness) {
             if (brightness < PowerManager.BRIGHTNESS_MIN
@@ -601,6 +651,22 @@
         }
 
         /**
+         * Sets the listener to get notified about changes in the display brightness.
+         *
+         * @param executor The executor where the callback is executed on.
+         * @param listener The listener to get notified when the display brightness has changed.
+         */
+        @SuppressLint("MissingGetterMatchingBuilder") // The hidden getter returns the AIDL object
+        @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER)
+        @NonNull
+        public Builder setBrightnessListener(@NonNull @CallbackExecutor Executor executor,
+                @NonNull BrightnessListener listener) {
+            mBrightnessListener = new BrightnessListenerDelegate(
+                    Objects.requireNonNull(executor), Objects.requireNonNull(listener));
+            return this;
+        }
+
+        /**
          * Builds the {@link VirtualDisplayConfig} instance.
          */
         @NonNull
@@ -620,7 +686,8 @@
                     mIsHomeSupported,
                     mDisplayCutout,
                     mIgnoreActivitySizeRestrictions,
-                    mDefaultBrightness);
+                    mDefaultBrightness,
+                    mBrightnessListener);
         }
     }
 }
diff --git a/core/java/android/hardware/input/KeyGlyphMap.java b/core/java/android/hardware/input/KeyGlyphMap.java
index f82d1cf..de5df91 100644
--- a/core/java/android/hardware/input/KeyGlyphMap.java
+++ b/core/java/android/hardware/input/KeyGlyphMap.java
@@ -133,6 +133,14 @@
             }
         };
 
+        public int getModifierState() {
+            return mModifierState;
+        }
+
+        public int getKeycode() {
+            return mKeycode;
+        }
+
         @Override
         public int describeContents() {
             return 0;
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 426cd69f..117d8fe 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -38,6 +38,8 @@
 import android.hardware.contexthub.HubEndpoint;
 import android.hardware.contexthub.HubEndpointInfo;
 import android.hardware.contexthub.HubServiceInfo;
+import android.hardware.contexthub.IContextHubEndpointDiscoveryCallback;
+import android.hardware.contexthub.IHubEndpointDiscoveryCallback;
 import android.hardware.contexthub.IHubEndpointLifecycleCallback;
 import android.os.Handler;
 import android.os.HandlerExecutor;
@@ -49,7 +51,9 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
 
 /**
@@ -202,6 +206,10 @@
     private Callback mCallback;
     private Handler mCallbackHandler;
 
+    /** A map of endpoint discovery callbacks currently registered */
+    private Map<IHubEndpointDiscoveryCallback, IContextHubEndpointDiscoveryCallback>
+            mDiscoveryCallbacks = new ConcurrentHashMap<>();
+
     /**
      * @deprecated Use {@code mCallback} instead.
      */
@@ -694,8 +702,6 @@
     @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
     @NonNull
     public List<HubDiscoveryInfo> findEndpoints(long endpointId) {
-        // TODO(b/379323274): Consider improving these getters to avoid racing with nano app load
-        //  timing.
         try {
             List<HubEndpointInfo> endpointInfos = mService.findEndpoints(endpointId);
             List<HubDiscoveryInfo> results = new ArrayList<>(endpointInfos.size());
@@ -720,8 +726,6 @@
     @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
     @NonNull
     public List<HubDiscoveryInfo> findEndpoints(@NonNull String serviceDescriptor) {
-        // TODO(b/379323274): Consider improving these getters to avoid racing with nano app load
-        //  timing.
         if (serviceDescriptor.isBlank()) {
             throw new IllegalArgumentException("Invalid service descriptor: " + serviceDescriptor);
         }
@@ -744,6 +748,188 @@
     }
 
     /**
+     * Creates an interface to invoke endpoint discovery callbacks to send down to the service.
+     *
+     * @param callback the callback to invoke at the client process
+     * @param executor the executor to invoke callbacks for this client
+     * @return the callback interface
+     */
+    private IContextHubEndpointDiscoveryCallback createDiscoveryCallback(
+            IHubEndpointDiscoveryCallback callback,
+            Executor executor,
+            @Nullable String serviceDescriptor) {
+        return new IContextHubEndpointDiscoveryCallback.Stub() {
+            @Override
+            public void onEndpointsStarted(HubEndpointInfo[] hubEndpointInfoList) {
+                if (hubEndpointInfoList.length == 0) {
+                    Log.w(TAG, "onEndpointsStarted: received empty discovery list");
+                    return;
+                }
+                executor.execute(
+                        () -> {
+                            // TODO(b/380293951): Refactor
+                            List<HubDiscoveryInfo> discoveryList =
+                                    new ArrayList<>(hubEndpointInfoList.length);
+                            for (HubEndpointInfo info : hubEndpointInfoList) {
+                                if (serviceDescriptor != null) {
+                                    for (HubServiceInfo sInfo : info.getServiceInfoCollection()) {
+                                        if (sInfo.getServiceDescriptor()
+                                                .equals(serviceDescriptor)) {
+                                            discoveryList.add(new HubDiscoveryInfo(info, sInfo));
+                                        }
+                                    }
+                                } else {
+                                    discoveryList.add(new HubDiscoveryInfo(info));
+                                }
+                            }
+                            if (discoveryList.isEmpty()) {
+                                Log.w(TAG, "onEndpointsStarted: no matching service descriptor");
+                            } else {
+                                callback.onEndpointsStarted(discoveryList);
+                            }
+                        });
+            }
+
+            @Override
+            public void onEndpointsStopped(HubEndpointInfo[] hubEndpointInfoList, int reason) {
+                if (hubEndpointInfoList.length == 0) {
+                    Log.w(TAG, "onEndpointsStopped: received empty discovery list");
+                    return;
+                }
+                executor.execute(
+                        () -> {
+                            List<HubDiscoveryInfo> discoveryList =
+                                    new ArrayList<>(hubEndpointInfoList.length);
+                            for (HubEndpointInfo info : hubEndpointInfoList) {
+                                if (serviceDescriptor != null) {
+                                    for (HubServiceInfo sInfo : info.getServiceInfoCollection()) {
+                                        if (sInfo.getServiceDescriptor()
+                                                .equals(serviceDescriptor)) {
+                                            discoveryList.add(new HubDiscoveryInfo(info, sInfo));
+                                        }
+                                    }
+                                } else {
+                                    discoveryList.add(new HubDiscoveryInfo(info));
+                                }
+                            }
+                            if (discoveryList.isEmpty()) {
+                                Log.w(TAG, "onEndpointsStopped: no matching service descriptor");
+                            } else {
+                                callback.onEndpointsStopped(discoveryList, reason);
+                            }
+                        });
+            }
+        };
+    }
+
+    /**
+     * Equivalent to {@link #registerEndpointDiscoveryCallback(long, IHubEndpointDiscoveryCallback,
+     * Executor)} with the default executor in the main thread.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+    @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+    public void registerEndpointDiscoveryCallback(
+            long endpointId, @NonNull IHubEndpointDiscoveryCallback callback) {
+        registerEndpointDiscoveryCallback(
+                endpointId, callback, new HandlerExecutor(Handler.getMain()));
+    }
+
+    /**
+     * Registers a callback to be notified when the hub endpoint with the corresponding endpoint ID
+     * has started or stopped.
+     *
+     * @param endpointId The identifier of the hub endpoint.
+     * @param callback The callback to be invoked.
+     * @param executor The executor to invoke the callback on.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+    @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+    public void registerEndpointDiscoveryCallback(
+            long endpointId,
+            @NonNull IHubEndpointDiscoveryCallback callback,
+            @NonNull Executor executor) {
+        Objects.requireNonNull(callback, "callback cannot be null");
+        Objects.requireNonNull(executor, "executor cannot be null");
+        IContextHubEndpointDiscoveryCallback iCallback =
+                createDiscoveryCallback(callback, executor, null);
+        try {
+            mService.registerEndpointDiscoveryCallbackId(endpointId, iCallback);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+
+        mDiscoveryCallbacks.put(callback, iCallback);
+    }
+
+    /**
+     * Equivalent to {@link #registerEndpointDiscoveryCallback(String,
+     * IHubEndpointDiscoveryCallback, Executor)} with the default executor in the main thread.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+    @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+    public void registerEndpointDiscoveryCallback(
+            @NonNull String serviceDescriptor, @NonNull IHubEndpointDiscoveryCallback callback) {
+        registerEndpointDiscoveryCallback(
+                serviceDescriptor, callback, new HandlerExecutor(Handler.getMain()));
+    }
+
+    /**
+     * Registers a callback to be notified when the hub endpoint with the corresponding service
+     * descriptor has started or stopped.
+     *
+     * @param serviceDescriptor The service descriptor of the hub endpoint.
+     * @param callback The callback to be invoked.
+     * @param executor The executor to invoke the callback on.
+     * @throws IllegalArgumentException if the serviceDescriptor is empty.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+    @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+    public void registerEndpointDiscoveryCallback(
+            @NonNull String serviceDescriptor,
+            @NonNull IHubEndpointDiscoveryCallback callback,
+            @NonNull Executor executor) {
+        Objects.requireNonNull(serviceDescriptor, "serviceDescriptor cannot be null");
+        Objects.requireNonNull(callback, "callback cannot be null");
+        Objects.requireNonNull(executor, "executor cannot be null");
+        if (serviceDescriptor.isBlank()) {
+            throw new IllegalArgumentException("Invalid service descriptor: " + serviceDescriptor);
+        }
+
+        IContextHubEndpointDiscoveryCallback iCallback =
+                createDiscoveryCallback(callback, executor, serviceDescriptor);
+        try {
+            mService.registerEndpointDiscoveryCallbackDescriptor(serviceDescriptor, iCallback);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+
+        mDiscoveryCallbacks.put(callback, iCallback);
+    }
+
+    /**
+     * Unregisters a previously registered endpoint discovery callback.
+     *
+     * @param callback The callback previously registered.
+     * @throws IllegalArgumentException If the callback was not previously registered.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+    @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+    public void unregisterEndpointDiscoveryCallback(
+            @NonNull IHubEndpointDiscoveryCallback callback) {
+        Objects.requireNonNull(callback, "callback cannot be null");
+        IContextHubEndpointDiscoveryCallback iCallback = mDiscoveryCallbacks.remove(callback);
+        if (iCallback == null) {
+            throw new IllegalArgumentException("Callback not previously registered");
+        }
+
+        try {
+            mService.unregisterEndpointDiscoveryCallback(iCallback);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Set a callback to receive messages from the context hub
      *
      * @param callback Callback object
diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl
index f9f41244..f14aadc 100644
--- a/core/java/android/hardware/location/IContextHubService.aidl
+++ b/core/java/android/hardware/location/IContextHubService.aidl
@@ -21,6 +21,7 @@
 import android.hardware.contexthub.HubEndpointInfo;
 import android.hardware.contexthub.IContextHubEndpoint;
 import android.hardware.contexthub.IContextHubEndpointCallback;
+import android.hardware.contexthub.IContextHubEndpointDiscoveryCallback;
 import android.hardware.location.ContextHubInfo;
 import android.hardware.location.ContextHubMessage;
 import android.hardware.location.HubInfo;
@@ -137,4 +138,16 @@
     // Register an endpoint with the context hub
     @EnforcePermission("ACCESS_CONTEXT_HUB")
     IContextHubEndpoint registerEndpoint(in HubEndpointInfo pendingEndpointInfo, in IContextHubEndpointCallback callback);
+
+    // Register an endpoint discovery callback (id)
+    @EnforcePermission("ACCESS_CONTEXT_HUB")
+    void registerEndpointDiscoveryCallbackId(long endpointId, in IContextHubEndpointDiscoveryCallback callback);
+
+    // Register an endpoint discovery callback (descriptor)
+    @EnforcePermission("ACCESS_CONTEXT_HUB")
+    void registerEndpointDiscoveryCallbackDescriptor(String serviceDescriptor, in IContextHubEndpointDiscoveryCallback callback);
+
+    // Unregister an endpoint with the context hub
+    @EnforcePermission("ACCESS_CONTEXT_HUB")
+    void unregisterEndpointDiscoveryCallback(in IContextHubEndpointDiscoveryCallback callback);
 }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 4bde8e2..5f3c15d 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1199,6 +1199,11 @@
                     // when the stylus is not down.
                     mPrivOps.setHandwritingSurfaceNotTouchable(true);
                     break;
+                case MotionEvent.ACTION_OUTSIDE:
+                    // TODO(b/350047836): determine if there is use-case for simultaneous touch
+                    //  and stylus handwriting and we shouldn't finish for that.
+                    finishStylusHandwriting();
+                    break;
             }
         }
 
@@ -3207,6 +3212,7 @@
             Log.d(TAG, "Setting new handwriting region for stylus handwriting "
                     + handwritingRegion + " from last " + mLastHandwritingRegion);
         }
+        mPrivOps.setHandwritingTouchableRegion(handwritingRegion);
         mLastHandwritingRegion = handwritingRegion;
     }
 
diff --git a/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java b/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java
index c0398ce..ded9415 100644
--- a/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java
+++ b/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java
@@ -23,18 +23,19 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
 import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY;
 import static android.net.vcn.VcnUnderlyingNetworkTemplate.getMatchCriteriaString;
+import static android.net.vcn.util.PersistableBundleUtils.INTEGER_DESERIALIZER;
+import static android.net.vcn.util.PersistableBundleUtils.INTEGER_SERIALIZER;
+import static android.net.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER;
+import static android.net.vcn.util.PersistableBundleUtils.STRING_SERIALIZER;
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility;
-import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_DESERIALIZER;
-import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_SERIALIZER;
-import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER;
-import static com.android.server.vcn.util.PersistableBundleUtils.STRING_SERIALIZER;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
 import android.net.NetworkCapabilities;
 import android.net.vcn.VcnUnderlyingNetworkTemplate.MatchCriteria;
+import android.net.vcn.util.PersistableBundleUtils;
 import android.os.PersistableBundle;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -44,7 +45,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
-import com.android.server.vcn.util.PersistableBundleUtils;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/core/java/android/net/vcn/VcnConfig.java b/core/java/android/net/vcn/VcnConfig.java
index a27e923..0d0efb2 100644
--- a/core/java/android/net/vcn/VcnConfig.java
+++ b/core/java/android/net/vcn/VcnConfig.java
@@ -18,10 +18,10 @@
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_TEST;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.vcn.util.PersistableBundleUtils.INTEGER_DESERIALIZER;
+import static android.net.vcn.util.PersistableBundleUtils.INTEGER_SERIALIZER;
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility;
-import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_DESERIALIZER;
-import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_SERIALIZER;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -29,6 +29,7 @@
 import android.content.Context;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
+import android.net.vcn.util.PersistableBundleUtils;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PersistableBundle;
@@ -37,7 +38,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
-import com.android.server.vcn.util.PersistableBundleUtils;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 3219ce8..067144e 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -32,12 +32,12 @@
 import android.net.NetworkCapabilities;
 import android.net.ipsec.ike.IkeTunnelConnectionParams;
 import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtils;
+import android.net.vcn.util.PersistableBundleUtils;
 import android.os.PersistableBundle;
 import android.util.ArraySet;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
-import com.android.server.vcn.util.PersistableBundleUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -789,11 +789,17 @@
         public Builder setMinUdpPort4500NatTimeoutSeconds(
                 @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS)
                         int minUdpPort4500NatTimeoutSeconds) {
-            Preconditions.checkArgument(
-                    minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET
-                            || minUdpPort4500NatTimeoutSeconds
-                                    >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS,
-                    "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET");
+            if (Flags.mainlineVcnModuleApi()) {
+                Preconditions.checkArgument(
+                        minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET
+                                || minUdpPort4500NatTimeoutSeconds
+                                        >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS,
+                        "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET");
+            } else {
+                Preconditions.checkArgument(
+                        minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS,
+                        "Timeout must be at least 120s");
+            }
 
             mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds;
             return this;
diff --git a/core/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java b/core/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java
index c7b2f18..770a8c1 100644
--- a/core/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java
+++ b/core/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java
@@ -17,22 +17,22 @@
 
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY;
+import static android.net.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER;
+import static android.net.vcn.util.PersistableBundleUtils.STRING_SERIALIZER;
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility;
-import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER;
-import static com.android.server.vcn.util.PersistableBundleUtils.STRING_SERIALIZER;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
 import android.net.NetworkCapabilities;
 import android.net.vcn.VcnUnderlyingNetworkTemplate.MatchCriteria;
+import android.net.vcn.util.PersistableBundleUtils;
 import android.os.PersistableBundle;
 import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.vcn.util.PersistableBundleUtils;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/core/java/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java b/core/java/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java
index ce5ec75..48c1b25 100644
--- a/core/java/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java
+++ b/core/java/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java
@@ -20,10 +20,10 @@
 
 import android.annotation.NonNull;
 import android.net.ipsec.ike.ChildSaProposal;
+import android.net.vcn.util.PersistableBundleUtils;
 import android.os.PersistableBundle;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.vcn.util.PersistableBundleUtils;
 
 import java.util.List;
 import java.util.Objects;
diff --git a/core/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java b/core/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java
index 853a52d..dc1ee36 100644
--- a/core/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java
+++ b/core/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java
@@ -28,10 +28,10 @@
 import android.net.eap.EapSessionConfig.EapSimConfig;
 import android.net.eap.EapSessionConfig.EapTtlsConfig;
 import android.net.eap.EapSessionConfig.EapUiccConfig;
+import android.net.vcn.util.PersistableBundleUtils;
 import android.os.PersistableBundle;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.vcn.util.PersistableBundleUtils;
 
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.X509Certificate;
diff --git a/core/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java b/core/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java
index 6acb34e..6e8616f 100644
--- a/core/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java
+++ b/core/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java
@@ -27,10 +27,10 @@
 import android.net.ipsec.ike.IkeIpv6AddrIdentification;
 import android.net.ipsec.ike.IkeKeyIdIdentification;
 import android.net.ipsec.ike.IkeRfc822AddrIdentification;
+import android.net.vcn.util.PersistableBundleUtils;
 import android.os.PersistableBundle;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.vcn.util.PersistableBundleUtils;
 
 import java.net.Inet4Address;
 import java.net.Inet6Address;
diff --git a/core/java/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java b/core/java/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java
index 1459671..b590148 100644
--- a/core/java/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java
+++ b/core/java/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java
@@ -20,10 +20,10 @@
 
 import android.annotation.NonNull;
 import android.net.ipsec.ike.IkeSaProposal;
+import android.net.vcn.util.PersistableBundleUtils;
 import android.os.PersistableBundle;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.vcn.util.PersistableBundleUtils;
 
 import java.util.List;
 import java.util.Objects;
diff --git a/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java
index d1531a1..aefac2e8 100644
--- a/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java
+++ b/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java
@@ -35,12 +35,12 @@
 import android.net.ipsec.ike.IkeSessionParams.IkeAuthEapConfig;
 import android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig;
 import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest;
+import android.net.vcn.util.PersistableBundleUtils;
 import android.os.PersistableBundle;
 import android.util.ArraySet;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.vcn.util.PersistableBundleUtils;
 
 import java.net.InetAddress;
 import java.security.PrivateKey;
diff --git a/core/java/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java b/core/java/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java
index 0c9ee84..469966a 100644
--- a/core/java/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java
+++ b/core/java/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java
@@ -18,11 +18,10 @@
 
 import android.annotation.NonNull;
 import android.net.ipsec.ike.SaProposal;
+import android.net.vcn.util.PersistableBundleUtils;
 import android.os.PersistableBundle;
 import android.util.Pair;
 
-import com.android.server.vcn.util.PersistableBundleUtils;
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
diff --git a/core/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java b/core/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java
index e62acac..3f4ba34 100644
--- a/core/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java
+++ b/core/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java
@@ -34,11 +34,11 @@
 import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6Address;
 import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer;
 import android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest;
+import android.net.vcn.util.PersistableBundleUtils;
 import android.os.PersistableBundle;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.vcn.util.PersistableBundleUtils;
 
 import java.net.Inet4Address;
 import java.net.Inet6Address;
diff --git a/services/core/java/com/android/server/vcn/util/LogUtils.java b/core/java/android/net/vcn/util/LogUtils.java
similarity index 96%
rename from services/core/java/com/android/server/vcn/util/LogUtils.java
rename to core/java/android/net/vcn/util/LogUtils.java
index 93728ce..7f7f852 100644
--- a/services/core/java/com/android/server/vcn/util/LogUtils.java
+++ b/core/java/android/net/vcn/util/LogUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.vcn.util;
+package android.net.vcn.util;
 
 import android.annotation.Nullable;
 import android.os.ParcelUuid;
diff --git a/services/core/java/com/android/server/vcn/util/MtuUtils.java b/core/java/android/net/vcn/util/MtuUtils.java
similarity index 99%
rename from services/core/java/com/android/server/vcn/util/MtuUtils.java
rename to core/java/android/net/vcn/util/MtuUtils.java
index 356c71f..c3123bc 100644
--- a/services/core/java/com/android/server/vcn/util/MtuUtils.java
+++ b/core/java/android/net/vcn/util/MtuUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.vcn.util;
+package android.net.vcn.util;
 
 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_3DES;
 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC;
diff --git a/services/core/java/com/android/server/vcn/util/OneWayBoolean.java b/core/java/android/net/vcn/util/OneWayBoolean.java
similarity index 96%
rename from services/core/java/com/android/server/vcn/util/OneWayBoolean.java
rename to core/java/android/net/vcn/util/OneWayBoolean.java
index e79bb2d..a7ef67b 100644
--- a/services/core/java/com/android/server/vcn/util/OneWayBoolean.java
+++ b/core/java/android/net/vcn/util/OneWayBoolean.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.vcn.util;
+package android.net.vcn.util;
 
 /**
  * OneWayBoolean is an abstraction for a boolean that MUST only ever be flipped from false to true
diff --git a/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java b/core/java/android/net/vcn/util/PersistableBundleUtils.java
similarity index 99%
rename from services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
rename to core/java/android/net/vcn/util/PersistableBundleUtils.java
index d6761a2..4dc42c7 100644
--- a/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
+++ b/core/java/android/net/vcn/util/PersistableBundleUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.vcn.util;
+package android.net.vcn.util;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
diff --git a/core/java/android/os/AggregateBatteryConsumer.java b/core/java/android/os/AggregateBatteryConsumer.java
index f0e12ca..f5fee4f 100644
--- a/core/java/android/os/AggregateBatteryConsumer.java
+++ b/core/java/android/os/AggregateBatteryConsumer.java
@@ -17,7 +17,6 @@
 package android.os;
 
 import android.annotation.NonNull;
-import android.util.proto.ProtoOutputStream;
 
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
@@ -100,19 +99,6 @@
         }
     }
 
-    void writePowerComponentModelProto(@NonNull ProtoOutputStream proto) {
-        for (int i = 0; i < POWER_COMPONENT_COUNT; i++) {
-            final int powerModel = getPowerModel(i);
-            if (powerModel == BatteryConsumer.POWER_MODEL_UNDEFINED) continue;
-
-            final long token = proto.start(BatteryUsageStatsAtomsProto.COMPONENT_MODELS);
-            proto.write(BatteryUsageStatsAtomsProto.PowerComponentModel.COMPONENT, i);
-            proto.write(BatteryUsageStatsAtomsProto.PowerComponentModel.POWER_MODEL,
-                    powerModelToProtoEnum(powerModel));
-            proto.end(token);
-        }
-    }
-
     /**
      * Builder for DeviceBatteryConsumer.
      */
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index 14b67f6..96ea168 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -161,18 +161,27 @@
 
     /**
      * Unspecified power model.
+     *
+     * @deprecated PowerModel is no longer supported
      */
+    @Deprecated
     public static final int POWER_MODEL_UNDEFINED = 0;
 
     /**
      * Power model that is based on average consumption rates that hardware components
      * consume in various states.
+     *
+     * @deprecated PowerModel is no longer supported
      */
+    @Deprecated
     public static final int POWER_MODEL_POWER_PROFILE = 1;
 
     /**
      * Power model that is based on energy consumption stats provided by PowerStats HAL.
+     *
+     * @deprecated PowerModel is no longer supported
      */
+    @Deprecated
     public static final int POWER_MODEL_ENERGY_CONSUMPTION = 2;
 
     /**
@@ -380,19 +389,17 @@
         public final @ScreenState int screenState;
         public final @PowerState int powerState;
 
-        final int mPowerModelColumnIndex;
         final int mPowerColumnIndex;
         final int mDurationColumnIndex;
 
         private Key(@PowerComponentId int powerComponentId, @ProcessState int processState,
-                @ScreenState int screenState, @PowerState int powerState, int powerModelColumnIndex,
+                @ScreenState int screenState, @PowerState int powerState,
                 int powerColumnIndex, int durationColumnIndex) {
             this.powerComponentId = powerComponentId;
             this.processState = processState;
             this.screenState = screenState;
             this.powerState = powerState;
 
-            mPowerModelColumnIndex = powerModelColumnIndex;
             mPowerColumnIndex = powerColumnIndex;
             mDurationColumnIndex = durationColumnIndex;
         }
@@ -577,11 +584,11 @@
      *
      * @param componentId The ID of the power component, e.g.
      *                    {@link BatteryConsumer#POWER_COMPONENT_CPU}.
+     * @deprecated PowerModel is no longer supported
      */
+    @Deprecated
     public @PowerModel int getPowerModel(@PowerComponentId int componentId) {
-        return mPowerComponents.getPowerModel(
-                mData.layout.getKeyOrThrow(componentId, PROCESS_STATE_UNSPECIFIED,
-                        SCREEN_STATE_UNSPECIFIED, POWER_STATE_UNSPECIFIED));
+        return POWER_MODEL_UNDEFINED;
     }
 
     /**
@@ -589,9 +596,11 @@
      *
      * @param key The key of the power component, obtained by calling {@link #getKey} or
      *            {@link #getKeys} method.
+     * @deprecated PowerModel is no longer supported
      */
+    @Deprecated
     public @PowerModel int getPowerModel(@NonNull BatteryConsumer.Key key) {
-        return mPowerComponents.getPowerModel(key);
+        return POWER_MODEL_UNDEFINED;
     }
 
     /**
@@ -657,20 +666,6 @@
     }
 
     /**
-     * Returns the name of the specified power model.  Intended for logging and debugging.
-     */
-    public static String powerModelToString(@BatteryConsumer.PowerModel int powerModel) {
-        switch (powerModel) {
-            case BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION:
-                return "energy consumption";
-            case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
-                return "power profile";
-            default:
-                return "";
-        }
-    }
-
-    /**
      * Returns the equivalent PowerModel enum for the specified power model.
      * {@see BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsage.PowerModel}
      */
@@ -857,10 +852,8 @@
 
     static class BatteryConsumerDataLayout {
         private static final Key[] KEY_ARRAY = new Key[0];
-        public static final int POWER_MODEL_NOT_INCLUDED = -1;
         public final String[] customPowerComponentNames;
         public final int customPowerComponentCount;
-        public final boolean powerModelsIncluded;
         public final boolean processStateDataIncluded;
         public final boolean screenStateDataIncluded;
         public final boolean powerStateDataIncluded;
@@ -872,11 +865,10 @@
         private SparseArray<Key[]> mPerComponentKeys;
 
         private BatteryConsumerDataLayout(int firstColumn, String[] customPowerComponentNames,
-                boolean powerModelsIncluded, boolean includeProcessStateData,
-                boolean includeScreenState, boolean includePowerState) {
+                boolean includeProcessStateData, boolean includeScreenState,
+                boolean includePowerState) {
             this.customPowerComponentNames = customPowerComponentNames;
             this.customPowerComponentCount = customPowerComponentNames.length;
-            this.powerModelsIncluded = powerModelsIncluded;
             this.processStateDataIncluded = includeProcessStateData;
             this.screenStateDataIncluded = includeScreenState;
             this.powerStateDataIncluded = includePowerState;
@@ -904,7 +896,7 @@
                         continue;
                     }
                     for (int i = 0; i < powerComponentIds.length; i++) {
-                        columnIndex = addKeys(keyList, powerModelsIncluded, includeProcessStateData,
+                        columnIndex = addKeys(keyList, includeProcessStateData,
                                 powerComponentIds[i], screenState, powerState, columnIndex);
                     }
                 }
@@ -934,13 +926,10 @@
             }
         }
 
-        private int addKeys(List<Key> keys, boolean powerModelsIncluded,
-                boolean includeProcessStateData, @PowerComponentId int componentId,
-                int screenState, int powerState, int columnIndex) {
+        private int addKeys(List<Key> keys, boolean includeProcessStateData,
+                @PowerComponentId int componentId, int screenState, int powerState,
+                int columnIndex) {
             keys.add(new Key(componentId, PROCESS_STATE_UNSPECIFIED, screenState, powerState,
-                    powerModelsIncluded
-                            ? columnIndex++
-                            : POWER_MODEL_NOT_INCLUDED,  // power model
                     columnIndex++,      // power
                     columnIndex++       // usage duration
             ));
@@ -956,9 +945,6 @@
                             continue;
                         }
                         keys.add(new Key(componentId, processState, screenState, powerState,
-                                powerModelsIncluded
-                                        ? columnIndex++
-                                        : POWER_MODEL_NOT_INCLUDED, // power model
                                 columnIndex++,      // power
                                 columnIndex++       // usage duration
                         ));
@@ -1016,7 +1002,7 @@
     }
 
     static BatteryConsumerDataLayout createBatteryConsumerDataLayout(
-            String[] customPowerComponentNames, boolean includePowerModels,
+            String[] customPowerComponentNames,
             boolean includeProcessStateData, boolean includeScreenStateData,
             boolean includePowerStateData) {
         int columnCount = BatteryConsumer.COLUMN_COUNT;
@@ -1025,8 +1011,7 @@
         columnCount = Math.max(columnCount, UserBatteryConsumer.COLUMN_COUNT);
 
         return new BatteryConsumerDataLayout(columnCount, customPowerComponentNames,
-                includePowerModels, includeProcessStateData, includeScreenStateData,
-                includePowerStateData);
+                includeProcessStateData, includeScreenStateData, includePowerStateData);
     }
 
     protected abstract static class BaseBuilder<T extends BaseBuilder<?>> {
@@ -1086,7 +1071,7 @@
         public T setConsumedPower(@PowerComponentId int componentId, double componentPower,
                 @PowerModel int powerModel) {
             mPowerComponentsBuilder.setConsumedPower(getKey(componentId, PROCESS_STATE_UNSPECIFIED),
-                    componentPower, powerModel);
+                    componentPower);
             return (T) this;
         }
 
@@ -1095,14 +1080,14 @@
         public T addConsumedPower(@PowerComponentId int componentId, double componentPower,
                 @PowerModel int powerModel) {
             mPowerComponentsBuilder.addConsumedPower(getKey(componentId, PROCESS_STATE_UNSPECIFIED),
-                    componentPower, powerModel);
+                    componentPower);
             return (T) this;
         }
 
         @SuppressWarnings("unchecked")
         @NonNull
         public T setConsumedPower(Key key, double componentPower, @PowerModel int powerModel) {
-            mPowerComponentsBuilder.setConsumedPower(key, componentPower, powerModel);
+            mPowerComponentsBuilder.setConsumedPower(key, componentPower);
             return (T) this;
         }
 
@@ -1110,21 +1095,14 @@
         @NonNull
         public T addConsumedPower(@PowerComponentId int componentId, double componentPower) {
             mPowerComponentsBuilder.addConsumedPower(getKey(componentId, PROCESS_STATE_UNSPECIFIED),
-                    componentPower, POWER_MODEL_UNDEFINED);
+                    componentPower);
             return (T) this;
         }
 
         @SuppressWarnings("unchecked")
         @NonNull
         public T addConsumedPower(Key key, double componentPower) {
-            mPowerComponentsBuilder.addConsumedPower(key, componentPower, POWER_MODEL_UNDEFINED);
-            return (T) this;
-        }
-
-        @SuppressWarnings("unchecked")
-        @NonNull
-        public T addConsumedPower(Key key, double componentPower, @PowerModel int powerModel) {
-            mPowerComponentsBuilder.addConsumedPower(key, componentPower, powerModel);
+            mPowerComponentsBuilder.addConsumedPower(key, componentPower);
             return (T) this;
         }
 
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 8b267bf..b63ad5f 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -167,76 +167,90 @@
     public static final String EXTRA_CHARGING_STATUS = "android.os.extra.CHARGING_STATUS";
 
     /**
-     * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
-     * Int value representing the battery's capacity level. These constants are key indicators of
-     * battery status and system capabilities, guiding power management decisions for both the
-     * system and apps:
-     * {@link #BATTERY_CAPACITY_LEVEL_UNSUPPORTED}: Feature not supported on this device.
-     * {@link #BATTERY_CAPACITY_LEVEL_UNKNOWN}: Battery status is unavailable or uninitialized.
-     * {@link #BATTERY_CAPACITY_LEVEL_CRITICAL}: Battery is critically low and the Android
-     * framework has been notified to schedule a shutdown by this value
-     * {@link #BATTERY_CAPACITY_LEVEL_LOW}: Android framework must limit background jobs to
-     * avoid impacting charging speed
-     * {@link #BATTERY_CAPACITY_LEVEL_NORMAL}: Battery level and charging rates are normal,
-     * battery temperature is within normal range and adapter power is enough to charge the
-     * battery at an acceptable rate. Android framework can run light background tasks without
-     * affecting charging performance severely.
-     * {@link #BATTERY_CAPACITY_LEVEL_HIGH}: Battery level is high, battery temperature is
-     * within normal range and adapter power is enough to charge the battery at an acceptable
-     * rate while running background loads. Android framework can run background tasks without
-     * affecting charging or battery performance.
-     * {@link #BATTERY_CAPACITY_LEVEL_FULL}: The battery is full, battery temperature is
-     * within normal range and adapter power is enough to sustain running background loads.
-     * Android framework can run background tasks without affecting the battery level or
-     * battery performance.
-     */
-
-    @FlaggedApi(FLAG_BATTERY_PART_STATUS_API)
-    public static final String EXTRA_CAPACITY_LEVEL = "android.os.extra.CAPACITY_LEVEL";
-
-    /**
-     * Battery capacity level is unsupported. @see EXTRA_CAPACITY_LEVEL
+     * Battery capacity level is unsupported.
+     *
+     * @see #EXTRA_CAPACITY_LEVEL
      */
     @FlaggedApi(FLAG_BATTERY_PART_STATUS_API)
     public static final int BATTERY_CAPACITY_LEVEL_UNSUPPORTED = -1;
 
     /**
-     * Battery capacity level is unknown. @see EXTRA_CAPACITY_LEVEL
+     * Battery capacity level is unknown.
+     *
+     * @see #EXTRA_CAPACITY_LEVEL
      */
     @FlaggedApi(FLAG_BATTERY_PART_STATUS_API)
     public static final int BATTERY_CAPACITY_LEVEL_UNKNOWN = 0;
 
     /**
-     * Battery capacity level is critical. @see EXTRA_CAPACITY_LEVEL
+     * Battery capacity level is critical. The Android framework has been notified to schedule
+     * a shutdown by this value.
+     *
+     * @see #EXTRA_CAPACITY_LEVEL
      */
     @FlaggedApi(FLAG_BATTERY_PART_STATUS_API)
     public static final int BATTERY_CAPACITY_LEVEL_CRITICAL = 1;
 
     /**
-     * Battery capacity level is low. @see EXTRA_CAPACITY_LEVEL
+     * Battery capacity level is low. The Android framework must limit background jobs to avoid
+     * impacting charging speed.
+     *
+     * @see #EXTRA_CAPACITY_LEVEL
      */
     @FlaggedApi(FLAG_BATTERY_PART_STATUS_API)
     public static final int BATTERY_CAPACITY_LEVEL_LOW = 2;
 
     /**
-     * Battery capacity level is normal. @see EXTRA_CAPACITY_LEVEL
+     * Battery capacity level is normal. Battery level and charging rates are normal, battery
+     * temperature is within the normal range, and adapter power is enough to charge the battery
+     * at an acceptable rate. The Android framework can run light background tasks without
+     * affecting charging performance severely.
+     *
+     * @see #EXTRA_CAPACITY_LEVEL
      */
     @FlaggedApi(FLAG_BATTERY_PART_STATUS_API)
     public static final int BATTERY_CAPACITY_LEVEL_NORMAL = 3;
 
     /**
-     * Battery capacity level is high. @see EXTRA_CAPACITY_LEVEL
+     * Battery capacity level is high. Battery level is high, battery temperature is within the
+     * normal range, and adapter power is enough to charge the battery at an acceptable rate
+     * while running background loads. The Android framework can run background tasks without
+     * affecting charging or battery performance.
+     *
+     * @see #EXTRA_CAPACITY_LEVEL
      */
     @FlaggedApi(FLAG_BATTERY_PART_STATUS_API)
     public static final int BATTERY_CAPACITY_LEVEL_HIGH = 4;
 
     /**
-     * Battery capacity level is full. @see EXTRA_CAPACITY_LEVEL
+     * Battery capacity level is full. The battery is full, the battery temperature is within the
+     * normal range, and adapter power is enough to sustain running background loads. The Android
+     * framework can run background tasks without affecting the battery level or battery
+     * performance.
+     *
+     * @see #EXTRA_CAPACITY_LEVEL
      */
     @FlaggedApi(FLAG_BATTERY_PART_STATUS_API)
     public static final int BATTERY_CAPACITY_LEVEL_FULL = 5;
 
     /**
+     * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+     * Int value representing the battery's capacity level. These constants are key indicators of
+     * battery status and system capabilities, guiding power management decisions for both the
+     * system and apps.
+     *
+     * @see #BATTERY_CAPACITY_LEVEL_UNSUPPORTED
+     * @see #BATTERY_CAPACITY_LEVEL_UNKNOWN
+     * @see #BATTERY_CAPACITY_LEVEL_CRITICAL
+     * @see #BATTERY_CAPACITY_LEVEL_LOW
+     * @see #BATTERY_CAPACITY_LEVEL_NORMAL
+     * @see #BATTERY_CAPACITY_LEVEL_HIGH
+     * @see #BATTERY_CAPACITY_LEVEL_FULL
+     */
+    @FlaggedApi(FLAG_BATTERY_PART_STATUS_API)
+    public static final String EXTRA_CAPACITY_LEVEL = "android.os.extra.CAPACITY_LEVEL";
+
+    /**
      * Extra for {@link android.content.Intent#ACTION_BATTERY_LEVEL_CHANGED}:
      * Contains list of Bundles representing battery events
      * @hide
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index 72e4cef..f913fcf 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -114,7 +114,6 @@
     static final String XML_ATTR_POWER_STATE = "power_state";
     static final String XML_ATTR_POWER = "power";
     static final String XML_ATTR_DURATION = "duration";
-    static final String XML_ATTR_MODEL = "model";
     static final String XML_ATTR_BATTERY_CAPACITY = "battery_capacity";
     static final String XML_ATTR_DISCHARGE_PERCENT = "discharge_pct";
     static final String XML_ATTR_DISCHARGE_LOWER = "discharge_lower";
@@ -155,7 +154,6 @@
     private final long mBatteryTimeRemainingMs;
     private final long mChargeTimeRemainingMs;
     private final String[] mCustomPowerComponentNames;
-    private final boolean mIncludesPowerModels;
     private final boolean mIncludesProcessStateData;
     private final boolean mIncludesScreenStateData;
     private final boolean mIncludesPowerStateData;
@@ -179,7 +177,6 @@
         mBatteryTimeRemainingMs = builder.mBatteryTimeRemainingMs;
         mChargeTimeRemainingMs = builder.mChargeTimeRemainingMs;
         mCustomPowerComponentNames = builder.mCustomPowerComponentNames;
-        mIncludesPowerModels = builder.mIncludePowerModels;
         mIncludesProcessStateData = builder.mIncludesProcessStateData;
         mIncludesScreenStateData = builder.mIncludesScreenStateData;
         mIncludesPowerStateData = builder.mIncludesPowerStateData;
@@ -364,14 +361,13 @@
         mBatteryTimeRemainingMs = source.readLong();
         mChargeTimeRemainingMs = source.readLong();
         mCustomPowerComponentNames = source.readStringArray();
-        mIncludesPowerModels = source.readBoolean();
         mIncludesProcessStateData = source.readBoolean();
         mIncludesScreenStateData = source.readBoolean();
         mIncludesPowerStateData = source.readBoolean();
 
         mBatteryConsumersCursorWindow = CursorWindow.newFromParcel(source);
         mBatteryConsumerDataLayout = BatteryConsumer.createBatteryConsumerDataLayout(
-                mCustomPowerComponentNames, mIncludesPowerModels, mIncludesProcessStateData,
+                mCustomPowerComponentNames, mIncludesProcessStateData,
                 mIncludesScreenStateData, mIncludesPowerStateData);
 
         final int numRows = mBatteryConsumersCursorWindow.getNumRows();
@@ -424,7 +420,6 @@
         dest.writeLong(mBatteryTimeRemainingMs);
         dest.writeLong(mChargeTimeRemainingMs);
         dest.writeStringArray(mCustomPowerComponentNames);
-        dest.writeBoolean(mIncludesPowerModels);
         dest.writeBoolean(mIncludesProcessStateData);
         dest.writeBoolean(mIncludesScreenStateData);
         dest.writeBoolean(mIncludesPowerStateData);
@@ -506,9 +501,6 @@
                 getDischargeDurationMs());
         deviceBatteryConsumer.writeStatsProto(proto,
                 BatteryUsageStatsAtomsProto.DEVICE_BATTERY_CONSUMER);
-        if (mIncludesPowerModels) {
-            deviceBatteryConsumer.writePowerComponentModelProto(proto);
-        }
         writeUidBatteryConsumersProto(proto, maxRawSize);
     }
 
@@ -629,7 +621,7 @@
 
             printPowerComponent(pw, prefix,
                     mBatteryConsumerDataLayout.getPowerComponentName(powerComponent),
-                    devicePowerMah, appsPowerMah, BatteryConsumer.POWER_MODEL_UNDEFINED,
+                    devicePowerMah, appsPowerMah,
                     deviceConsumer.getUsageDurationMillis(powerComponent));
         }
 
@@ -716,23 +708,15 @@
             printPowerComponent(pw, prefix,
                     mBatteryConsumerDataLayout.getPowerComponentName(powerComponent),
                     devicePowerMah, appsPowerMah,
-                    mIncludesPowerModels ? deviceConsumer.getPowerModel(powerComponent)
-                            : BatteryConsumer.POWER_MODEL_UNDEFINED,
                     deviceConsumer.getUsageDurationMillis(dimensions));
         }
     }
 
     private void printPowerComponent(PrintWriter pw, String prefix, String label,
-            double devicePowerMah, double appsPowerMah, int powerModel, long durationMs) {
+            double devicePowerMah, double appsPowerMah, long durationMs) {
         StringBuilder sb = new StringBuilder();
         sb.append(prefix).append("    ").append(label).append(": ")
                 .append(BatteryStats.formatCharge(devicePowerMah));
-        if (powerModel != BatteryConsumer.POWER_MODEL_UNDEFINED
-                && powerModel != BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
-            sb.append(" [");
-            sb.append(BatteryConsumer.powerModelToString(powerModel));
-            sb.append("]");
-        }
         sb.append(" apps: ").append(BatteryStats.formatCharge(appsPowerMah));
         if (durationMs != 0) {
             sb.append(" duration: ");
@@ -828,7 +812,7 @@
                 final boolean includesPowerStateData = parser.getAttributeBoolean(null,
                         XML_ATTR_PREFIX_INCLUDES_POWER_STATE_DATA, false);
 
-                builder = new Builder(customComponentNames.toArray(new String[0]), true,
+                builder = new Builder(customComponentNames.toArray(new String[0]),
                         includesProcStateData, includesScreenStateData, includesPowerStateData, 0);
 
                 builder.setStatsStartTimestamp(
@@ -913,7 +897,6 @@
         private final CursorWindow mBatteryConsumersCursorWindow;
         @NonNull
         private final String[] mCustomPowerComponentNames;
-        private final boolean mIncludePowerModels;
         private final boolean mIncludesProcessStateData;
         private final boolean mIncludesScreenStateData;
         private final boolean mIncludesPowerStateData;
@@ -938,22 +921,21 @@
         private BatteryStatsHistory mBatteryStatsHistory;
 
         public Builder(@NonNull String[] customPowerComponentNames) {
-            this(customPowerComponentNames, false, false, false, false, 0);
+            this(customPowerComponentNames, false, false, false, 0);
         }
 
-        public Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels,
+        public Builder(@NonNull String[] customPowerComponentNames,
                 boolean includeProcessStateData, boolean includeScreenStateData,
                 boolean includesPowerStateData, double minConsumedPowerThreshold) {
             mBatteryConsumersCursorWindow =
                     new CursorWindow(null, BATTERY_CONSUMER_CURSOR_WINDOW_SIZE);
             onCursorWindowAllocated(mBatteryConsumersCursorWindow);
             mBatteryConsumerDataLayout = BatteryConsumer.createBatteryConsumerDataLayout(
-                    customPowerComponentNames, includePowerModels, includeProcessStateData,
+                    customPowerComponentNames, includeProcessStateData,
                     includeScreenStateData, includesPowerStateData);
             mBatteryConsumersCursorWindow.setNumColumns(mBatteryConsumerDataLayout.columnCount);
 
             mCustomPowerComponentNames = customPowerComponentNames;
-            mIncludePowerModels = includePowerModels;
             mIncludesProcessStateData = includeProcessStateData;
             mIncludesScreenStateData = includeScreenStateData;
             mIncludesPowerStateData = includesPowerStateData;
diff --git a/core/java/android/os/BatteryUsageStatsQuery.java b/core/java/android/os/BatteryUsageStatsQuery.java
index 6325b00..6e67578 100644
--- a/core/java/android/os/BatteryUsageStatsQuery.java
+++ b/core/java/android/os/BatteryUsageStatsQuery.java
@@ -24,6 +24,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
 
 /**
  * Query parameters for the {@link BatteryStatsManager#getBatteryUsageStats()} call.
@@ -65,12 +66,6 @@
      */
     public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY = 0x0002;
 
-    /**
-     * Indicates that identifiers of power models used for computations of power
-     * consumption should be included in the BatteryUsageStats.
-     */
-    public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS = 0x0004;
-
     public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA = 0x0008;
 
     public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_VIRTUAL_UIDS = 0x0010;
@@ -202,7 +197,24 @@
         return mAggregatedToTimestamp;
     }
 
+    @Override
+    public String toString() {
+        return "BatteryUsageStatsQuery{"
+                + "mFlags=" + Integer.toHexString(mFlags)
+                + ", mUserIds=" + Arrays.toString(mUserIds)
+                + ", mMaxStatsAgeMs=" + mMaxStatsAgeMs
+                + ", mAggregatedFromTimestamp=" + mAggregatedFromTimestamp
+                + ", mAggregatedToTimestamp=" + mAggregatedToTimestamp
+                + ", mMonotonicStartTime=" + mMonotonicStartTime
+                + ", mMonotonicEndTime=" + mMonotonicEndTime
+                + ", mMinConsumedPowerThreshold=" + mMinConsumedPowerThreshold
+                + ", mPowerComponents=" + Arrays.toString(mPowerComponents)
+                + '}';
+    }
+
     private BatteryUsageStatsQuery(Parcel in) {
+        mMonotonicStartTime = in.readLong();
+        mMonotonicEndTime = in.readLong();
         mFlags = in.readInt();
         mUserIds = new int[in.readInt()];
         in.readIntArray(mUserIds);
@@ -215,6 +227,8 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(mMonotonicStartTime);
+        dest.writeLong(mMonotonicEndTime);
         dest.writeInt(mFlags);
         dest.writeInt(mUserIds.length);
         dest.writeIntArray(mUserIds);
@@ -311,7 +325,10 @@
          * power monitoring data is available.
          *
          * Should only be used for testing and debugging.
+         *
+         * @deprecated PowerModel is no longer supported
          */
+        @Deprecated
         public Builder powerProfileModeledOnly() {
             mFlags |= BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL;
             return this;
@@ -322,9 +339,10 @@
          * of power consumption.
          *
          * Should only be used for testing and debugging.
+         * @deprecated PowerModel is no longer supported
          */
+        @Deprecated
         public Builder includePowerModels() {
-            mFlags |= BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS;
             return this;
         }
 
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index c2e9260..9b39c62 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1546,6 +1546,57 @@
     }
 
     /**
+     * Convert a major.minor version String like "36.1" to an int that
+     * represents both major and minor version.
+     *
+     * @param version the String to parse
+     * @return an int encoding the major and minor version
+     * @throws IllegalArgumentException if the string could not be converted into an int
+     *
+     * @hide
+     */
+    @SuppressWarnings("FlaggedApi") // SDK_INT_MULTIPLIER is defined in this file
+    public static @SdkIntFull int parseFullVersion(@NonNull String version) {
+        int index = version.indexOf('.');
+        int major;
+        int minor = 0;
+        try {
+            if (index == -1) {
+                major = Integer.parseInt(version);
+            } else {
+                major = Integer.parseInt(version.substring(0, index));
+                minor = Integer.parseInt(version.substring(index + 1));
+            }
+            if (major < 0 || minor < 0) {
+                throw new NumberFormatException();
+            }
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException("failed to parse '" + version
+                    + "' as a major.minor version code");
+        }
+        return major * VERSION_CODES_FULL.SDK_INT_MULTIPLIER + minor;
+    }
+
+    /**
+     * Convert an int representing a major.minor version like SDK_INT_FULL to a
+     * human readable string. The returned string is only intended for debug
+     * and error messages.
+     *
+     * @param version the int to convert to a string
+     * @return a String representing the same major.minor version as the int passed in
+     * @throws IllegalArgumentException if {@code version} is negative
+     *
+     * @hide
+     */
+    public static String fullVersionToString(@SdkIntFull int version) {
+        if (version < 0) {
+            throw new IllegalArgumentException("failed to convert '" + version
+                    + "' to string: not a valid major.minor version code");
+        }
+        return String.format("%d.%d", getMajorSdkVersion(version), getMinorSdkVersion(version));
+    }
+
+    /**
      * The vendor API for 2024 Q2
      *
      * <p>For Android 14-QPR3 and later, the vendor API level is completely decoupled from the SDK
diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
index 4c9f08d..4769681 100644
--- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java
+++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
@@ -19,8 +19,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.TestApi;
-import android.app.ActivityThread;
-import android.app.Instrumentation;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Process;
 import android.os.UserHandle;
@@ -88,14 +86,20 @@
     // queue for async messages when inserting a message at the tail.
     private int mAsyncMessageCount;
 
-    /*
+    /**
      * Select between two implementations of message queue. The legacy implementation is used
      * by default as it provides maximum compatibility with applications and tests that
      * reach into MessageQueue via the mMessages field. The concurrent implemmentation is used for
      * system processes and provides a higher level of concurrency and higher enqueue throughput
      * than the legacy implementation.
      */
-    private boolean mUseConcurrent;
+    private final boolean mUseConcurrent;
+
+    /**
+     * Caches process-level checks that determine `mUseConcurrent`.
+     * This is to avoid redoing checks that shouldn't change during the process's lifetime.
+     */
+    private static Boolean sIsProcessAllowedToUseConcurrent = null;
 
     @RavenwoodRedirect
     private native static long nativeInit();
@@ -112,34 +116,41 @@
     private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
 
     MessageQueue(boolean quitAllowed) {
-        // Concurrent mode modifies behavior that is observable via reflection and is commonly used
-        // by tests.
-        // For now, we limit it to system processes to avoid breaking apps and their tests.
-        mUseConcurrent = UserHandle.isCore(Process.myUid());
-        // Even then, we don't use it if instrumentation is loaded as it breaks some
-        // platform tests.
-        final Instrumentation instrumentation = getInstrumentation();
-        mUseConcurrent &= instrumentation == null || !instrumentation.isInstrumenting();
-        // We can lift this restriction in the future after we've made it possible for test authors
-        // to test Looper and MessageQueue without resorting to reflection.
+        if (sIsProcessAllowedToUseConcurrent == null) {
+            // Concurrent mode modifies behavior that is observable via reflection and is commonly
+            // used by tests.
+            // For now, we limit it to system processes to avoid breaking apps and their tests.
+            boolean useConcurrent = UserHandle.isCore(Process.myUid());
+
+            // Some platform tests run in system UIDs.
+            // Use this awful heuristic to detect them.
+            if (useConcurrent) {
+                final String processName = Process.myProcessName();
+                if (processName == null
+                        || processName.contains("test")
+                        || processName.contains("Test")) {
+                    useConcurrent = false;
+                }
+            }
+
+            // We can lift this restriction in the future after we've made it possible for test
+            // authors to test Looper and MessageQueue without resorting to reflection.
+
+            // Holdback study.
+            if (useConcurrent && Flags.messageQueueForceLegacy()) {
+                useConcurrent = false;
+            }
+
+            sIsProcessAllowedToUseConcurrent = useConcurrent;
+            mUseConcurrent = useConcurrent;
+        } else {
+            mUseConcurrent = sIsProcessAllowedToUseConcurrent;
+        }
 
         mQuitAllowed = quitAllowed;
         mPtr = nativeInit();
     }
 
-    @android.ravenwood.annotation.RavenwoodReplace(blockedBy = ActivityThread.class)
-    private static Instrumentation getInstrumentation() {
-        final ActivityThread activityThread = ActivityThread.currentActivityThread();
-        if (activityThread != null) {
-            return activityThread.getInstrumentation();
-        }
-        return null;
-    }
-
-    private static Instrumentation getInstrumentation$ravenwood() {
-        return null; // Instrumentation not supported on Ravenwood yet.
-    }
-
     @Override
     protected void finalize() throws Throwable {
         try {
diff --git a/core/java/android/os/CpuHeadroomParams.java b/core/java/android/os/CpuHeadroomParams.java
index f0d4f7d..072c012 100644
--- a/core/java/android/os/CpuHeadroomParams.java
+++ b/core/java/android/os/CpuHeadroomParams.java
@@ -18,10 +18,13 @@
 
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
 import android.os.health.SystemHealthManager;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
 
 /**
  * Headroom request params used by {@link SystemHealthManager#getCpuHeadroom(CpuHeadroomParams)}.
@@ -53,6 +56,10 @@
      */
     public static final int CPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1;
 
+    private static final int CALCULATION_WINDOW_MILLIS_MIN = 50;
+    private static final int CALCULATION_WINDOW_MILLIS_MAX = 10000;
+    private static final int MAX_TID_COUNT = 5;
+
     /**
      * Sets the headroom calculation type.
      * <p>
@@ -83,6 +90,61 @@
     }
 
     /**
+     * Sets the headroom calculation window size in milliseconds.
+     * <p>
+     *
+     * @param windowMillis the window size in milliseconds ranges from [50, 10000]. The smaller the
+     *                     window size, the larger fluctuation in the headroom value should be
+     *                     expected. The default value can be retrieved from the
+     *                     {@link #getCalculationWindowMillis}. The device will try to use the
+     *                     closest feasible window size to this param.
+     * @throws IllegalArgumentException if the window size is not in allowed range.
+     */
+    public void setCalculationWindowMillis(
+            @IntRange(from = CALCULATION_WINDOW_MILLIS_MIN, to =
+                    CALCULATION_WINDOW_MILLIS_MAX) int windowMillis) {
+        if (windowMillis < CALCULATION_WINDOW_MILLIS_MIN
+                || windowMillis > CALCULATION_WINDOW_MILLIS_MAX) {
+            throw new IllegalArgumentException("Invalid calculation window: " + windowMillis);
+        }
+        mInternal.calculationWindowMillis = windowMillis;
+    }
+
+    /**
+     * Gets the headroom calculation window size in milliseconds.
+     * <p>
+     * This will return the default value chosen by the device if the params is not set.
+     */
+    public @IntRange(from = CALCULATION_WINDOW_MILLIS_MIN, to =
+            CALCULATION_WINDOW_MILLIS_MAX) long getCalculationWindowMillis() {
+        return mInternal.calculationWindowMillis;
+    }
+
+    /**
+     * Sets the thread TIDs to track.
+     * <p>
+     * The TIDs should belong to the same of the process that will the headroom call. And they
+     * should not have different core affinity.
+     * <p>
+     * If not set, the headroom will be based on the PID of the process making the call.
+     *
+     * @param tids non-empty list of TIDs, maximum 5.
+     * @throws IllegalArgumentException if the list size is not in allowed range or TID is not
+     *                                  positive.
+     */
+    public void setTids(@NonNull int... tids) {
+        if (tids.length == 0 || tids.length > MAX_TID_COUNT) {
+            throw new IllegalArgumentException("Invalid number of TIDs: " + tids.length);
+        }
+        for (int tid : tids) {
+            if (tid <= 0) {
+                throw new IllegalArgumentException("Invalid TID: " + tid);
+            }
+        }
+        mInternal.tids = Arrays.copyOf(tids, tids.length);
+    }
+
+    /**
      * @hide
      */
     public CpuHeadroomParamsInternal getInternal() {
diff --git a/core/java/android/os/CpuHeadroomParamsInternal.aidl b/core/java/android/os/CpuHeadroomParamsInternal.aidl
index 6cc4699..d572f965 100644
--- a/core/java/android/os/CpuHeadroomParamsInternal.aidl
+++ b/core/java/android/os/CpuHeadroomParamsInternal.aidl
@@ -25,6 +25,8 @@
 @JavaDerive(equals = true, toString = true)
 parcelable CpuHeadroomParamsInternal {
     boolean usesDeviceHeadroom = false;
+    int[] tids;
+    int calculationWindowMillis = 1000;
     CpuHeadroomParams.CalculationType calculationType = CpuHeadroomParams.CalculationType.MIN;
     CpuHeadroomParams.SelectionType selectionType = CpuHeadroomParams.SelectionType.ALL;
 }
diff --git a/core/java/android/os/GpuHeadroomParams.java b/core/java/android/os/GpuHeadroomParams.java
index efb2a28..126ee8c 100644
--- a/core/java/android/os/GpuHeadroomParams.java
+++ b/core/java/android/os/GpuHeadroomParams.java
@@ -18,6 +18,7 @@
 
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.os.health.SystemHealthManager;
 
 import java.lang.annotation.Retention;
@@ -53,6 +54,9 @@
      */
     public static final int GPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1;
 
+    private static final int CALCULATION_WINDOW_MILLIS_MIN = 50;
+    private static final int CALCULATION_WINDOW_MILLIS_MAX = 10000;
+
     /**
      * Sets the headroom calculation type.
      * <p>
@@ -71,7 +75,7 @@
 
     /**
      * Gets the headroom calculation type.
-     * Default to {@link #GPU_HEADROOM_CALCULATION_TYPE_MIN} if not set.
+     * Default to {@link #GPU_HEADROOM_CALCULATION_TYPE_MIN} if the params is not set.
      */
     public @GpuHeadroomCalculationType int getCalculationType() {
         @GpuHeadroomCalculationType int validatedType = switch ((int) mInternal.calculationType) {
@@ -83,6 +87,37 @@
     }
 
     /**
+     * Sets the headroom calculation window size in milliseconds.
+     * <p>
+     *
+     * @param windowMillis the window size in milliseconds ranges from [50, 10000]. The smaller the
+     *                     window size, the larger fluctuation in the headroom value should be
+     *                     expected. The default value can be retrieved from the
+     *                     {@link #getCalculationWindowMillis}. The device will try to use the
+     *                     closest feasible window size to this param.
+     * @throws IllegalArgumentException if the window is invalid.
+     */
+    public void setCalculationWindowMillis(
+            @IntRange(from = CALCULATION_WINDOW_MILLIS_MIN, to =
+                    CALCULATION_WINDOW_MILLIS_MAX) int windowMillis) {
+        if (windowMillis < CALCULATION_WINDOW_MILLIS_MIN
+                || windowMillis > CALCULATION_WINDOW_MILLIS_MAX) {
+            throw new IllegalArgumentException("Invalid calculation window: " + windowMillis);
+        }
+        mInternal.calculationWindowMillis = windowMillis;
+    }
+
+    /**
+     * Gets the headroom calculation window size in milliseconds.
+     * <p>
+     * This will return the default value chosen by the device if not set.
+     */
+    public @IntRange(from = CALCULATION_WINDOW_MILLIS_MIN, to =
+            CALCULATION_WINDOW_MILLIS_MAX) int getCalculationWindowMillis() {
+        return mInternal.calculationWindowMillis;
+    }
+
+    /**
      * @hide
      */
     public GpuHeadroomParamsInternal getInternal() {
diff --git a/core/java/android/os/GpuHeadroomParamsInternal.aidl b/core/java/android/os/GpuHeadroomParamsInternal.aidl
index 20309e7..40d5d8e 100644
--- a/core/java/android/os/GpuHeadroomParamsInternal.aidl
+++ b/core/java/android/os/GpuHeadroomParamsInternal.aidl
@@ -24,5 +24,6 @@
  */
 @JavaDerive(equals = true, toString = true)
 parcelable GpuHeadroomParamsInternal {
+    int calculationWindowMillis = 1000;
     GpuHeadroomParams.CalculationType calculationType = GpuHeadroomParams.CalculationType.MIN;
 }
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 94768d1..8f6a508 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -98,6 +98,7 @@
     private static final int VULKAN_1_1 = 0x00401000;
     private static final int VULKAN_1_2 = 0x00402000;
     private static final int VULKAN_1_3 = 0x00403000;
+    private static final int VULKAN_1_4 = 0x00404000;
 
     // Values for UPDATABLE_DRIVER_ALL_APPS
     // 0: Default (Invalid values fallback to default as well)
@@ -179,6 +180,10 @@
     private int getVulkanVersion(PackageManager pm) {
         // PackageManager doesn't have an API to retrieve the version of a specific feature, and we
         // need to avoid retrieving all system features here and looping through them.
+        if (pm.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, VULKAN_1_4)) {
+            return VULKAN_1_4;
+        }
+
         if (pm.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, VULKAN_1_3)) {
             return VULKAN_1_3;
         }
diff --git a/core/java/android/os/IHintManager.aidl b/core/java/android/os/IHintManager.aidl
index a043da9..f1936b5 100644
--- a/core/java/android/os/IHintManager.aidl
+++ b/core/java/android/os/IHintManager.aidl
@@ -21,7 +21,9 @@
 import android.os.GpuHeadroomParamsInternal;
 import android.os.IHintSession;
 import android.os.SessionCreationConfig;
+import android.hardware.power.CpuHeadroomResult;
 import android.hardware.power.ChannelConfig;
+import android.hardware.power.GpuHeadroomResult;
 import android.hardware.power.SessionConfig;
 import android.hardware.power.SessionTag;
 
@@ -53,9 +55,9 @@
      */
     @nullable ChannelConfig getSessionChannel(in IBinder token);
     oneway void closeSessionChannel();
-    float[] getCpuHeadroom(in CpuHeadroomParamsInternal params);
+    @nullable CpuHeadroomResult getCpuHeadroom(in CpuHeadroomParamsInternal params);
     long getCpuHeadroomMinIntervalMillis();
-    float getGpuHeadroom(in GpuHeadroomParamsInternal params);
+    @nullable GpuHeadroomResult getGpuHeadroom(in GpuHeadroomParamsInternal params);
     long getGpuHeadroomMinIntervalMillis();
 
     /**
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index e63b664..bfcc5cc 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -89,10 +89,13 @@
 per-file DdmSyncStageUpdater.java = sanglardf@google.com, rpaquay@google.com
 
 # PerformanceHintManager
-per-file PerformanceHintManager.java = file:/ADPF_OWNERS
+per-file CpuHeadroom*.aidl = file:/ADPF_OWNERS
+per-file GpuHeadroom*.aidl = file:/ADPF_OWNERS
+per-file CpuHeadroom*.java = file:/ADPF_OWNERS
+per-file GpuHeadroom*.java = file:/ADPF_OWNERS
 per-file WorkDuration.java = file:/ADPF_OWNERS
-per-file IHintManager.aidl = file:/ADPF_OWNERS
-per-file IHintSession.aidl = file:/ADPF_OWNERS
+per-file *Hint* = file:/ADPF_OWNERS
+per-file *Session* = file:/ADPF_OWNERS
 
 # IThermal interfaces
 per-file IThermal* = file:/THERMAL_OWNERS
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
index d116e07..4db1f1b 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -15,7 +15,6 @@
  */
 package android.os;
 
-import static android.os.BatteryConsumer.BatteryConsumerDataLayout.POWER_MODEL_NOT_INCLUDED;
 import static android.os.BatteryConsumer.POWER_COMPONENT_ANY;
 import static android.os.BatteryConsumer.POWER_COMPONENT_BASE;
 import static android.os.BatteryConsumer.POWER_STATE_ANY;
@@ -156,15 +155,6 @@
         return mData.layout.getPowerComponentName(componentId);
     }
 
-    @BatteryConsumer.PowerModel
-    int getPowerModel(BatteryConsumer.Key key) {
-        if (key.mPowerModelColumnIndex == POWER_MODEL_NOT_INCLUDED) {
-            throw new IllegalStateException(
-                    "Power model IDs were not requested in the BatteryUsageStatsQuery");
-        }
-        return mData.getInt(key.mPowerModelColumnIndex);
-    }
-
     /**
      * Returns the amount of time used by the specified component, e.g. CPU, WiFi etc.
      *
@@ -378,10 +368,6 @@
             if (durationMs != 0) {
                 serializer.attributeLong(null, BatteryUsageStats.XML_ATTR_DURATION, durationMs);
             }
-            if (mData.layout.powerModelsIncluded) {
-                serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_MODEL,
-                        getPowerModel(key));
-            }
             serializer.endTag(null, BatteryUsageStats.XML_TAG_COMPONENT);
         }
         serializer.endTag(null, BatteryUsageStats.XML_TAG_POWER_COMPONENTS);
@@ -411,7 +397,6 @@
                         int powerState = POWER_STATE_UNSPECIFIED;
                         double powerMah = 0;
                         long durationMs = 0;
-                        int model = BatteryConsumer.POWER_MODEL_UNDEFINED;
                         for (int i = 0; i < parser.getAttributeCount(); i++) {
                             switch (parser.getAttributeName(i)) {
                                 case BatteryUsageStats.XML_ATTR_ID:
@@ -432,14 +417,11 @@
                                 case BatteryUsageStats.XML_ATTR_DURATION:
                                     durationMs = parser.getAttributeLong(i);
                                     break;
-                                case BatteryUsageStats.XML_ATTR_MODEL:
-                                    model = parser.getAttributeInt(i);
-                                    break;
                             }
                         }
                         final BatteryConsumer.Key key = builder.mData.layout.getKey(componentId,
                                 processState, screenState, powerState);
-                        builder.addConsumedPower(key, powerMah, model);
+                        builder.addConsumedPower(key, powerMah);
                         builder.addUsageDurationMillis(key, durationMs);
                         break;
                     }
@@ -453,43 +435,28 @@
      * Builder for PowerComponents.
      */
     static final class Builder {
-        private static final byte POWER_MODEL_UNINITIALIZED = -1;
-
         private final BatteryConsumer.BatteryConsumerData mData;
         private final double mMinConsumedPowerThreshold;
 
         Builder(BatteryConsumer.BatteryConsumerData data, double minConsumedPowerThreshold) {
             mData = data;
             mMinConsumedPowerThreshold = minConsumedPowerThreshold;
-            for (BatteryConsumer.Key key : mData.layout.keys) {
-                if (key.mPowerModelColumnIndex != POWER_MODEL_NOT_INCLUDED) {
-                    mData.putInt(key.mPowerModelColumnIndex, POWER_MODEL_UNINITIALIZED);
-                }
-            }
         }
 
         /**
-         * @deprecated use {@link #addConsumedPower(BatteryConsumer.Key, double, int)}
+         * @deprecated use {@link #addConsumedPower(BatteryConsumer.Key, double)}
          */
         @Deprecated
         @NonNull
-        public Builder setConsumedPower(BatteryConsumer.Key key, double componentPower,
-                int powerModel) {
+        public Builder setConsumedPower(BatteryConsumer.Key key, double componentPower) {
             mData.putDouble(key.mPowerColumnIndex, componentPower);
-            if (key.mPowerModelColumnIndex != POWER_MODEL_NOT_INCLUDED) {
-                mData.putInt(key.mPowerModelColumnIndex, powerModel);
-            }
             return this;
         }
 
         @NonNull
-        public Builder addConsumedPower(BatteryConsumer.Key key, double componentPower,
-                int powerModel) {
+        public Builder addConsumedPower(BatteryConsumer.Key key, double componentPower) {
             mData.putDouble(key.mPowerColumnIndex,
                     mData.getDouble(key.mPowerColumnIndex) + componentPower);
-            if (key.mPowerModelColumnIndex != POWER_MODEL_NOT_INCLUDED) {
-                mData.putInt(key.mPowerModelColumnIndex, powerModel);
-            }
             return this;
         }
 
@@ -547,28 +514,6 @@
                             mData.getLong(key.mDurationColumnIndex)
                                     + otherData.getLong(otherKey.mDurationColumnIndex));
                 }
-                if (key.mPowerModelColumnIndex == POWER_MODEL_NOT_INCLUDED) {
-                    continue;
-                }
-
-                boolean undefined = false;
-                if (otherKey.mPowerModelColumnIndex == POWER_MODEL_NOT_INCLUDED) {
-                    undefined = true;
-                } else {
-                    final int powerModel = mData.getInt(key.mPowerModelColumnIndex);
-                    int otherPowerModel = otherData.getInt(otherKey.mPowerModelColumnIndex);
-                    if (powerModel == POWER_MODEL_UNINITIALIZED) {
-                        mData.putInt(key.mPowerModelColumnIndex, otherPowerModel);
-                    } else if (powerModel != otherPowerModel
-                            && otherPowerModel != POWER_MODEL_UNINITIALIZED) {
-                        undefined = true;
-                    }
-                }
-
-                if (undefined) {
-                    mData.putInt(key.mPowerModelColumnIndex,
-                            BatteryConsumer.POWER_MODEL_UNDEFINED);
-                }
             }
         }
 
@@ -594,13 +539,6 @@
         @NonNull
         public PowerComponents build() {
             for (BatteryConsumer.Key key : mData.layout.keys) {
-                if (key.mPowerModelColumnIndex != POWER_MODEL_NOT_INCLUDED) {
-                    if (mData.getInt(key.mPowerModelColumnIndex) == POWER_MODEL_UNINITIALIZED) {
-                        mData.putInt(key.mPowerModelColumnIndex,
-                                BatteryConsumer.POWER_MODEL_UNDEFINED);
-                    }
-                }
-
                 if (mMinConsumedPowerThreshold != 0) {
                     if (mData.getDouble(key.mPowerColumnIndex) < mMinConsumedPowerThreshold) {
                         mData.putDouble(key.mPowerColumnIndex, 0);
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index d5630fd..4123209 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -214,7 +214,7 @@
             if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
                 try {
                     mBinder.removeFrozenStateChangeCallback(this);
-                } catch (UnsupportedOperationException e) {
+                } catch (UnsupportedOperationException | IllegalArgumentException e) {
                     // The kernel does not support frozen notifications. Ignore the error and move
                     // on.
                 }
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 5a53bc15..7e73a5d 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -3846,7 +3846,7 @@
     }
 
     /**
-     * Return the time when the context user was unlocked elapsed milliseconds since boot,
+     * Return the time when the calling user was unlocked elapsed milliseconds since boot,
      * or 0 if not unlocked.
      *
      * @hide
@@ -3878,7 +3878,11 @@
             Manifest.permission.MANAGE_USERS,
             Manifest.permission.CREATE_USERS,
             Manifest.permission.QUERY_USERS})
+    @CachedProperty(api = "user_manager_user_data")
     public UserInfo getUserInfo(@UserIdInt int userId) {
+        if (android.multiuser.Flags.cacheUserInfoReadOnly()) {
+            return UserManagerCache.getUserInfo(mService::getUserInfo, userId);
+        }
         try {
             return mService.getUserInfo(userId);
         } catch (RemoteException re) {
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index 5ac53f1..3001fbd 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -4,6 +4,15 @@
 
 # keep-sorted start block=yes newline_separated=yes
 flag {
+     # Holdback study for concurrent MessageQueue.
+     # Do not promote beyond trunkfood.
+     namespace: "system_performance"
+     name: "message_queue_force_legacy"
+     description: "Whether to holdback concurrent MessageQueue (force legacy)."
+     bug: "336880969"
+}
+
+flag {
     name: "adpf_gpu_report_actual_work_duration"
     is_exported: true
     namespace: "game"
@@ -222,6 +231,15 @@
 }
 
 flag {
+     name: "message_queue_testability"
+     namespace: "system_performance"
+     is_exported: true
+     description: "Whether MessageQueue implements test APIs."
+     bug: "379472827"
+     is_fixed_read_only: true
+}
+
+flag {
     name: "network_time_uses_shared_memory"
     namespace: "system_performance"
     description: "SystemClock.currentNetworkTimeMillis() reads network time offset from shared memory"
diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java
index 4db9bc3..cd79e41 100644
--- a/core/java/android/os/health/SystemHealthManager.java
+++ b/core/java/android/os/health/SystemHealthManager.java
@@ -23,6 +23,8 @@
 import android.annotation.SystemService;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
+import android.hardware.power.CpuHeadroomResult;
+import android.hardware.power.GpuHeadroomResult;
 import android.os.BatteryStats;
 import android.os.Build;
 import android.os.Bundle;
@@ -110,15 +112,16 @@
     }
 
     /**
-     * Provides an estimate of global available CPU headroom of the calling thread.
+     * Provides an estimate of global available CPU headroom.
      * <p>
      *
      * @param  params params to customize the CPU headroom calculation, null to use default params.
-     * @return a single value a {@code Float.NaN} if it's temporarily unavailable.
+     * @return a single value headroom or a {@code Float.NaN} if it's temporarily unavailable.
      *         A valid value is ranged from [0, 100], where 0 indicates no more CPU resources can be
      *         granted.
-     * @throws UnsupportedOperationException if the API is unsupported or the request params can't
-     *         be served.
+     * @throws UnsupportedOperationException if the API is unsupported.
+     * @throws SecurityException if the TIDs of the params don't belong to the same process.
+     * @throws IllegalStateException if the TIDs of the params don't have the same affinity setting.
      */
     @FlaggedApi(android.os.Flags.FLAG_CPU_GPU_HEADROOMS)
     public @FloatRange(from = 0f, to = 100f) float getCpuHeadroom(
@@ -127,8 +130,12 @@
             throw new UnsupportedOperationException();
         }
         try {
-            return mHintManager.getCpuHeadroom(
-                    params != null ? params.getInternal() : new CpuHeadroomParamsInternal())[0];
+            final CpuHeadroomResult ret = mHintManager.getCpuHeadroom(
+                    params != null ? params.getInternal() : new CpuHeadroomParamsInternal());
+            if (ret == null || ret.getTag() != CpuHeadroomResult.globalHeadroom) {
+                return Float.NaN;
+            }
+            return ret.getGlobalHeadroom();
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
@@ -144,8 +151,7 @@
      * @return a single value headroom or a {@code Float.NaN} if it's temporarily unavailable.
      *         A valid value is ranged from [0, 100], where 0 indicates no more GPU resources can be
      *         granted.
-     * @throws UnsupportedOperationException if the API is unsupported or the request params can't
-     *         be served.
+     * @throws UnsupportedOperationException if the API is unsupported.
      */
     @FlaggedApi(android.os.Flags.FLAG_CPU_GPU_HEADROOMS)
     public @FloatRange(from = 0f, to = 100f) float getGpuHeadroom(
@@ -154,8 +160,12 @@
             throw new UnsupportedOperationException();
         }
         try {
-            return mHintManager.getGpuHeadroom(
+            final GpuHeadroomResult ret = mHintManager.getGpuHeadroom(
                     params != null ? params.getInternal() : new GpuHeadroomParamsInternal());
+            if (ret == null || ret.getTag() != GpuHeadroomResult.globalHeadroom) {
+                return Float.NaN;
+            }
+            return ret.getGlobalHeadroom();
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 55ba4af..b5139b5 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -58,7 +58,7 @@
     is_fixed_read_only: true
     namespace: "permissions"
     description: "enable enhanced confirmation incall apis"
-    bug: "310220212"
+    bug: "364535720"
 }
 
 flag {
@@ -67,7 +67,7 @@
     is_fixed_read_only: true
     namespace: "permissions"
     description: "enable the blocking of certain app installs during an unknown call"
-    bug: "310220212"
+    bug: "364535720"
 }
 
 flag {
@@ -436,3 +436,30 @@
     description: "Use profile labels from UserManager for default app section titles to allow partner customization"
     bug: "358369931"
 }
+
+flag {
+    name: "wallet_role_cross_user_enabled"
+    is_exported: true
+    is_fixed_read_only: true
+    namespace: "wallet_integration"
+    description: "Enable the Wallet role within profiles"
+    bug: "356107987"
+}
+
+flag {
+    name: "text_classifier_choice_api_enabled"
+    is_fixed_read_only: true
+    is_exported: true
+    namespace: "permissions"
+    description: "API change to enable getTextClassifier by type"
+    bug: "377229653"
+}
+
+flag {
+    name: "updatable_text_classifier_for_otp_detection_enabled"
+    is_fixed_read_only: true
+    is_exported: true
+    namespace: "permissions"
+    description: "Enables text classifier for OTP detection that is updatable from mainline module"
+    bug: "377229653"
+}
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index f6bdc18..e4a3c9f 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -16,6 +16,8 @@
 
 package android.preference;
 
+import static android.window.OnBackInvokedDispatcher.PRIORITY_DEFAULT;
+
 import android.animation.LayoutTransition;
 import android.annotation.Nullable;
 import android.annotation.StringRes;
@@ -54,6 +56,8 @@
 import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.TextView;
+import android.window.OnBackInvokedCallback;
+import android.window.WindowOnBackInvokedDispatcher;
 
 import com.android.internal.util.XmlUtils;
 
@@ -209,6 +213,8 @@
     private int mPreferenceHeaderItemResId = 0;
     private boolean mPreferenceHeaderRemoveEmptyIcon = false;
 
+    private final OnBackInvokedCallback mOnBackInvokedCallback = this::onBackInvoked;
+
     /**
      * The starting request code given out to preference framework.
      */
@@ -699,10 +705,26 @@
                 skipButton.setVisibility(View.VISIBLE);
             }
         }
+        updateBackCallbackRegistrationState();
     }
 
     @Override
     public void onBackPressed() {
+        onBackInvoked();
+    }
+
+    private void updateBackCallbackRegistrationState() {
+        if (!WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(this)) return;
+        if (mCurHeader != null && mSinglePane && getFragmentManager().getBackStackEntryCount() == 0
+                && getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT) == null) {
+            getOnBackInvokedDispatcher()
+                    .registerOnBackInvokedCallback(PRIORITY_DEFAULT, mOnBackInvokedCallback);
+        } else {
+            getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mOnBackInvokedCallback);
+        }
+    }
+
+    private void onBackInvoked() {
         if (mCurHeader != null && mSinglePane && getFragmentManager().getBackStackEntryCount() == 0
                 && getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT) == null) {
             mCurHeader = null;
@@ -713,9 +735,10 @@
                 showBreadCrumbs(mActivityTitle, null);
             }
             getListView().clearChoices();
-        } else {
+        } else if (!WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(this)) {
             super.onBackPressed();
         }
+        updateBackCallbackRegistrationState();
     }
 
     /**
@@ -1221,6 +1244,7 @@
             getListView().clearChoices();
         }
         showBreadCrumbs(header);
+        updateBackCallbackRegistrationState();
     }
 
     void showBreadCrumbs(Header header) {
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 99ff38b..8e379e8 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -10859,6 +10859,28 @@
                 "vnd.android.cursor.item/contact_metadata_sync_state";
     }
 
+    /**
+     * This exception is thrown when an attempt is made to perform a write operation
+     * on a contact or contact group targeting a local account or a SIM account,
+     * and the operation is not permitted under the current conditions.
+     * The local account can be retrieved using {@link RawContacts#getLocalAccountName(Context)}
+     * and {@link RawContacts#getLocalAccountType(Context)}.
+     * SIM accounts can be retrieved using {@link SimContacts#getSimAccounts(ContentResolver)}.
+     *
+     * <p>Local and SIM accounts have limitations that may prevent write operations
+     * due to their nature, underlying implementation, or the current system state.
+     * For example, the SIM card may be full, read-only, or not present.
+     *
+     * <p>The specific conditions under which write operations are permitted on
+     * local or SIM accounts can vary.
+     */
+    @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
+    public static class LocalSimContactsWriteException extends IllegalArgumentException {
+        public LocalSimContactsWriteException(@NonNull String s) {
+            super(s);
+        }
+    }
+
     private static Bundle nullSafeCall(@NonNull ContentResolver resolver, @NonNull Uri uri,
             @NonNull String method, @Nullable String arg, @Nullable Bundle extras) {
         try (ContentProviderClient client = resolver.acquireContentProviderClient(uri)) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 23f7629..8d054f4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6374,6 +6374,14 @@
         public static final String LOCALE_PREFERENCES = "locale_preferences";
 
         /**
+         * User can change the region from region settings. This records user's preferred region.
+         *
+         * E.g. : if user's locale is en-US, this will record US
+         * @hide
+         */
+        public static final String PREFERRED_REGION = "preferred_region";
+
+        /**
          * Setting to enable camera flash notification feature.
          * <ul>
          *     <li> 0 = Off
@@ -6547,6 +6555,7 @@
             PRIVATE_SETTINGS.add(DEFAULT_DEVICE_FONT_SCALE);
             PRIVATE_SETTINGS.add(MOUSE_REVERSE_VERTICAL_SCROLLING);
             PRIVATE_SETTINGS.add(MOUSE_SWAP_PRIMARY_BUTTON);
+            PRIVATE_SETTINGS.add(PREFERRED_REGION);
         }
 
         /**
@@ -10999,6 +11008,25 @@
                 "emergency_gesture_ui_last_started_millis";
 
         /**
+         * Whether double tap the power button gesture is enabled.
+         *
+         * @hide
+         */
+        @Readable
+        public static final String DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED =
+                "double_tap_power_button_gesture_enabled";
+
+        /**
+         * Double tap power button gesture behavior.
+         * 0 = Camera launch
+         * 1 = Wallet launch
+         * @hide
+         */
+        @Readable
+        public static final String DOUBLE_TAP_POWER_BUTTON_GESTURE =
+                "double_tap_power_button_gesture";
+
+        /**
          * Whether the camera launch gesture to double tap the power button when the screen is off
          * should be disabled.
          *
diff --git a/core/java/android/security/advancedprotection/AdvancedProtectionManager.java b/core/java/android/security/advancedprotection/AdvancedProtectionManager.java
index 9fe0dda..0302faf 100644
--- a/core/java/android/security/advancedprotection/AdvancedProtectionManager.java
+++ b/core/java/android/security/advancedprotection/AdvancedProtectionManager.java
@@ -281,7 +281,7 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(Manifest.permission.SET_ADVANCED_PROTECTION_MODE)
+    @RequiresPermission(Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE)
     public void setAdvancedProtectionEnabled(boolean enabled) {
         try {
             mService.setAdvancedProtectionEnabled(enabled);
@@ -297,7 +297,7 @@
      */
     @SystemApi
     @NonNull
-    @RequiresPermission(Manifest.permission.SET_ADVANCED_PROTECTION_MODE)
+    @RequiresPermission(Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE)
     public List<AdvancedProtectionFeature> getAdvancedProtectionFeatures() {
         try {
             return mService.getAdvancedProtectionFeatures();
diff --git a/core/java/android/security/advancedprotection/IAdvancedProtectionService.aidl b/core/java/android/security/advancedprotection/IAdvancedProtectionService.aidl
index 6830763..1939f82 100644
--- a/core/java/android/security/advancedprotection/IAdvancedProtectionService.aidl
+++ b/core/java/android/security/advancedprotection/IAdvancedProtectionService.aidl
@@ -31,8 +31,8 @@
     void registerAdvancedProtectionCallback(IAdvancedProtectionCallback callback);
     @EnforcePermission("QUERY_ADVANCED_PROTECTION_MODE")
     void unregisterAdvancedProtectionCallback(IAdvancedProtectionCallback callback);
-    @EnforcePermission("SET_ADVANCED_PROTECTION_MODE")
+    @EnforcePermission("MANAGE_ADVANCED_PROTECTION_MODE")
     void setAdvancedProtectionEnabled(boolean enabled);
-    @EnforcePermission("SET_ADVANCED_PROTECTION_MODE")
+    @EnforcePermission("MANAGE_ADVANCED_PROTECTION_MODE")
     List<AdvancedProtectionFeature> getAdvancedProtectionFeatures();
 }
\ No newline at end of file
diff --git a/core/java/android/security/advancedprotection/OWNERS b/core/java/android/security/advancedprotection/OWNERS
index ddac8ed..bfb7e16 100644
--- a/core/java/android/security/advancedprotection/OWNERS
+++ b/core/java/android/security/advancedprotection/OWNERS
@@ -2,7 +2,6 @@
 
 achim@google.com
 azharaa@google.com
-cpinelli@google.com
 eranm@google.com
 hanikazmi@google.com
 haok@google.com
diff --git a/core/java/android/security/intrusiondetection/IIntrusionDetectionEventTransport.aidl b/core/java/android/security/intrusiondetection/IIntrusionDetectionEventTransport.aidl
index 8759f72..eab1c15 100644
--- a/core/java/android/security/intrusiondetection/IIntrusionDetectionEventTransport.aidl
+++ b/core/java/android/security/intrusiondetection/IIntrusionDetectionEventTransport.aidl
@@ -15,6 +15,7 @@
  */
 
 package android.security.intrusiondetection;
+
 import android.security.intrusiondetection.IntrusionDetectionEvent;
 
 import com.android.internal.infra.AndroidFuture;
@@ -24,18 +25,20 @@
     /**
      * Initialize the server side.
      */
-    void initialize(in AndroidFuture<int> resultFuture);
+    void initialize(in AndroidFuture<boolean> resultFuture);
 
     /**
-     * Send intrusiondetection logging data to the backup destination.
+     * Send intrusiondetection logging data to the transport destination.
      * The data is a list of IntrusionDetectionEvent.
      * The IntrusionDetectionEvent is an abstract class that represents
-     * different type of events.
+     * different types of events.
      */
-    void addData(in List<IntrusionDetectionEvent> events, in AndroidFuture<int> resultFuture);
+    void addData(
+        in List<IntrusionDetectionEvent> events,
+        in AndroidFuture<boolean> resultFuture);
 
     /**
      * Release the binder to the server.
      */
-    void release(in AndroidFuture<int> resultFuture);
+    void release(in AndroidFuture<boolean> resultFuture);
 }
diff --git a/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java b/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java
index 538acf9..b479ca7 100644
--- a/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java
+++ b/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java
@@ -22,6 +22,7 @@
 import android.app.admin.ConnectEvent;
 import android.app.admin.DnsEvent;
 import android.app.admin.SecurityLog.SecurityEvent;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.security.Flags;
@@ -31,14 +32,36 @@
 
 /**
  * A class that represents a intrusiondetection event.
+ *
  * @hide
  */
+@SystemApi
 @FlaggedApi(Flags.FLAG_AFL_API)
 public final class IntrusionDetectionEvent implements Parcelable {
     private static final String TAG = "IntrusionDetectionEvent";
 
+    /**
+     * Event type representing a security-related event.
+     * This type is associated with a {@link SecurityEvent} object.
+     *
+     * @see SecurityEvent
+     */
     public static final int SECURITY_EVENT = 0;
+
+    /**
+     * Event type representing a network DNS event.
+     * This type is associated with a {@link DnsEvent} object.
+     *
+     * @see DnsEvent
+     */
     public static final int NETWORK_EVENT_DNS = 1;
+
+    /**
+     * Event type representing a network connection event.
+     * This type is associated with a {@link ConnectEvent} object.
+     *
+     * @see ConnectEvent
+     */
     public static final int NETWORK_EVENT_CONNECT = 2;
 
     /** @hide */
@@ -67,6 +90,12 @@
                 }
             };
 
+    /**
+     * Creates an IntrusionDetectionEvent object with a
+     * {@link SecurityEvent} object as the event source.
+     *
+     * @param securityEvent The SecurityEvent object.
+     */
     public IntrusionDetectionEvent(@NonNull SecurityEvent securityEvent) {
         mType = SECURITY_EVENT;
         mSecurityEvent = securityEvent;
@@ -74,6 +103,12 @@
         mNetworkEventConnect = null;
     }
 
+    /**
+     * Creates an IntrusionDetectionEvent object with a
+     * {@link DnsEvent} object as the event source.
+     *
+     * @param dnsEvent The DnsEvent object.
+     */
     public IntrusionDetectionEvent(@NonNull DnsEvent dnsEvent) {
         mType = NETWORK_EVENT_DNS;
         mNetworkEventDns = dnsEvent;
@@ -81,6 +116,12 @@
         mNetworkEventConnect = null;
     }
 
+    /**
+     * Creates an IntrusionDetectionEvent object with a
+     * {@link ConnectEvent} object as the event source.
+     *
+     * @param connectEvent The ConnectEvent object.
+     */
     public IntrusionDetectionEvent(@NonNull ConnectEvent connectEvent) {
         mType = NETWORK_EVENT_CONNECT;
         mNetworkEventConnect = connectEvent;
diff --git a/core/java/android/security/intrusiondetection/IntrusionDetectionEventTransport.java b/core/java/android/security/intrusiondetection/IntrusionDetectionEventTransport.java
new file mode 100644
index 0000000..2e2d0f7
--- /dev/null
+++ b/core/java/android/security/intrusiondetection/IntrusionDetectionEventTransport.java
@@ -0,0 +1,145 @@
+/*
+ * 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.security.intrusiondetection;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.SuppressLint;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.IBinder;
+import android.util.CloseGuard;
+
+import android.security.Flags;
+import android.security.intrusiondetection.IntrusionDetectionEvent;
+import android.security.intrusiondetection.IIntrusionDetectionEventTransport;
+
+import com.android.internal.infra.AndroidFuture;
+
+import java.lang.AutoCloseable;
+import java.util.List;
+
+/**
+ * A class that provides a stable API for transporting intrusion detection events
+ * to a transport location, such as a file or a network endpoint.
+ *
+ * This class acts as a bridge between the {@link IIntrusionDetectionEventTransport}
+ * interface and its implementations. It allows system components to add intrusion
+ * detection events ({@link IntrusionDetectionEvent}) to a transport queue,
+ * which will then be delivered to the specified location.
+ *
+ * Usage:
+ * 1. Obtain an instance of {@link IntrusionDetectionEventTransport} using the constructor.
+ * 2. Initialize the transport by calling {@link #initialize()}.
+ * 3. Add events to the transport queue using {@link #addData(List)}.
+ * 4. Release the transport when finished by calling {@link #release()}.
+ *
+ * Key Components:
+ * - {@link IIntrusionDetectionEventTransport}: The underlying AIDL interface
+ *     for interacting with transport implementations.
+ * - {@link IntrusionDetectionEvent}: Represents a single event.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_AFL_API)
+@SuppressLint("NotCloseable")
+public class IntrusionDetectionEventTransport {
+    IIntrusionDetectionEventTransport mBinderImpl = new TransportImpl();
+
+    /**
+     * Returns the binder interface for this transport.
+     */
+    @NonNull
+    public IBinder getBinder() {
+        return mBinderImpl.asBinder();
+    }
+
+    /**
+     * Initializes the transport.
+     *
+     * @return whether the initialization was successful.
+     */
+    public boolean initialize() {
+        return false;
+    }
+
+    /**
+     * Adds data to the transport.
+     *
+     * @param events the events to add.
+     * @return whether the addition was successful.
+     */
+    public boolean addData(@NonNull List<IntrusionDetectionEvent> events) {
+        return false;
+    }
+
+    /**
+     * Releases the transport.
+     *
+     * The release() method is a callback implemented by the concrete transport
+     * endpoint.
+     * The "SuppressLint" annotation is used to allow the release() method to be
+     * included in the API without requiring the class to implement AutoCloseable.
+     *
+     * @return whether the release was successful.
+     */
+    public boolean release() {
+        return false;
+    }
+
+    /**
+     * Bridge between the actual IIntrusionDetectionEventTransport implementation
+     * and the stable API.  If the binder interface needs to change, we use this
+     * layer to translate so that we can decouple those framework-side changes
+     * from the IntrusionDetectionEventTransport implementations.
+     */
+    class TransportImpl extends IIntrusionDetectionEventTransport.Stub {
+        @Override
+        public void initialize(AndroidFuture<Boolean> resultFuture) {
+            try {
+                boolean result = IntrusionDetectionEventTransport.this.initialize();
+                resultFuture.complete(result);
+            } catch (RuntimeException e) {
+                resultFuture.cancel(/* mayInterruptIfRunning */ true);
+            }
+        }
+
+        @Override
+        public void addData(
+            List<IntrusionDetectionEvent> events,
+            AndroidFuture<Boolean> resultFuture) {
+            try {
+                boolean result = IntrusionDetectionEventTransport.this.addData(events);
+                resultFuture.complete(result);
+            } catch (RuntimeException e) {
+                resultFuture.cancel(/* mayInterruptIfRunning */ true);
+            }
+        }
+
+        @Override
+        public void release(AndroidFuture<Boolean> resultFuture) {
+            try {
+                boolean result = IntrusionDetectionEventTransport.this.release();
+                resultFuture.complete(result);
+            } catch (RuntimeException e) {
+                resultFuture.cancel(/* mayInterruptIfRunning */ true);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/security/responsible_apis_flags.aconfig b/core/java/android/security/responsible_apis_flags.aconfig
index 6c92991..2007a5f 100644
--- a/core/java/android/security/responsible_apis_flags.aconfig
+++ b/core/java/android/security/responsible_apis_flags.aconfig
@@ -96,6 +96,29 @@
 }
 
 flag {
+    name: "prevent_intent_redirect_show_toast_if_nested_keys_not_collected"
+    namespace: "responsible_apis"
+    description: "Prevent intent redirect attacks by showing a toast if not yet collected"
+    bug: "361143368"
+    is_fixed_read_only: true
+}
+
+flag {
+    name: "prevent_intent_redirect_throw_exception_if_nested_keys_not_collected"
+    namespace: "responsible_apis"
+    description: "Prevent intent redirect attacks by throwing exception if the intent does not collect nested keys"
+    bug: "361143368"
+}
+
+flag {
+    name: "prevent_intent_redirect_collect_nested_keys_on_server_if_not_collected"
+    namespace: "responsible_apis"
+    description: "Prevent intent redirect attacks by collecting nested keys on server if not yet collected"
+    bug: "361143368"
+    is_fixed_read_only: true
+}
+
+flag {
     name: "enable_intent_matching_flags"
     is_exported: true
     namespace: "permissions"
@@ -110,3 +133,16 @@
     description: "Android Advanced Protection Mode Feature: Disable Install Unknown Sources"
     bug: "369361373"
 }
+
+flag {
+    name: "aapm_feature_memory_tagging_extension"
+    namespace: "responsible_apis"
+    description: "Android Advanced Protection Mode Feature: Memory Tagging Extension"
+    bug: "378931989"
+}
+flag {
+    name: "aapm_feature_disable_cellular_2g"
+    namespace: "responsible_apis"
+    description: "Android Advanced Protection Mode Feature: Disable Cellular 2G"
+    bug: "377748286"
+}
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index 14a14e6..fba8e42 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -170,6 +170,9 @@
                 }
                 parcel.writeInt(event.mSaveDialogNotShowReason);
                 parcel.writeInt(event.mUiType);
+                if (Flags.addLastFocusedIdToFillEventHistory()) {
+                    parcel.writeParcelable(event.mFocusedId, 0);
+                }
             }
         }
     }
@@ -375,6 +378,8 @@
         @UiType
         private final int mUiType;
 
+        @Nullable private final AutofillId mFocusedId;
+
         /**
          * Returns the type of the event.
          *
@@ -388,7 +393,7 @@
         @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
         @Nullable
         public AutofillId getFocusedId() {
-            return null;
+            return mFocusedId;
         }
 
         /**
@@ -624,6 +629,7 @@
          * @param manuallyFilledDatasetIds The ids of datasets that had values matching the
          * respective entry on {@code manuallyFilledFieldIds}.
          * @param detectedFieldClassifications the field classification matches.
+         * @param focusedId the field which was focused at the time of event trigger
          *
          * @throws IllegalArgumentException If the length of {@code changedFieldIds} and
          * {@code changedDatasetIds} doesn't match.
@@ -640,11 +646,12 @@
                 @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
                 @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
                 @Nullable AutofillId[] detectedFieldIds,
-                @Nullable FieldClassification[] detectedFieldClassifications) {
+                @Nullable FieldClassification[] detectedFieldClassifications,
+                @Nullable AutofillId focusedId) {
             this(eventType, datasetId, clientState, selectedDatasetIds, ignoredDatasetIds,
                     changedFieldIds, changedDatasetIds, manuallyFilledFieldIds,
                     manuallyFilledDatasetIds, detectedFieldIds, detectedFieldClassifications,
-                    NO_SAVE_UI_REASON_NONE);
+                    NO_SAVE_UI_REASON_NONE, focusedId);
         }
 
         /**
@@ -665,6 +672,7 @@
          * respective entry on {@code manuallyFilledFieldIds}.
          * @param detectedFieldClassifications the field classification matches.
          * @param saveDialogNotShowReason The reason why a save dialog was not shown.
+         * @param focusedId the field which was focused at the time of event trigger
          *
          * @throws IllegalArgumentException If the length of {@code changedFieldIds} and
          * {@code changedDatasetIds} doesn't match.
@@ -682,11 +690,12 @@
                 @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
                 @Nullable AutofillId[] detectedFieldIds,
                 @Nullable FieldClassification[] detectedFieldClassifications,
-                int saveDialogNotShowReason) {
+                int saveDialogNotShowReason,
+                @Nullable AutofillId focusedId) {
             this(eventType, datasetId, clientState, selectedDatasetIds, ignoredDatasetIds,
                     changedFieldIds, changedDatasetIds, manuallyFilledFieldIds,
                     manuallyFilledDatasetIds, detectedFieldIds, detectedFieldClassifications,
-                    saveDialogNotShowReason, UI_TYPE_UNKNOWN);
+                    saveDialogNotShowReason, UI_TYPE_UNKNOWN, focusedId);
         }
 
         /**
@@ -708,6 +717,7 @@
          * @param detectedFieldClassifications the field classification matches.
          * @param saveDialogNotShowReason The reason why a save dialog was not shown.
          * @param uiType The ui presentation type for fill suggestion.
+         * @param focusedId the field which was focused at the time of event trigger
          *
          * @throws IllegalArgumentException If the length of {@code changedFieldIds} and
          * {@code changedDatasetIds} doesn't match.
@@ -725,7 +735,7 @@
                 @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
                 @Nullable AutofillId[] detectedFieldIds,
                 @Nullable FieldClassification[] detectedFieldClassifications,
-                int saveDialogNotShowReason, int uiType) {
+                int saveDialogNotShowReason, int uiType, @Nullable AutofillId focusedId) {
             mEventType = Preconditions.checkArgumentInRange(eventType, 0,
                     TYPE_VIEW_REQUESTED_AUTOFILL, "eventType");
             mDatasetId = datasetId;
@@ -756,6 +766,7 @@
                     NO_SAVE_UI_REASON_NONE, NO_SAVE_UI_REASON_DATASET_MATCH,
                     "saveDialogNotShowReason");
             mUiType = uiType;
+            mFocusedId = focusedId;
         }
 
         @Override
@@ -852,13 +863,17 @@
                                 : null;
                         final int saveDialogNotShowReason = parcel.readInt();
                         final int uiType = parcel.readInt();
+                        AutofillId focusedId = null;
+                        if (Flags.addLastFocusedIdToFillEventHistory()) {
+                            focusedId = parcel.readParcelable(null, AutofillId.class);
+                        }
 
                         selection.addEvent(new Event(eventType, datasetId, clientState,
                                 selectedDatasetIds, ignoredDatasets,
                                 changedFieldIds, changedDatasetIds,
                                 manuallyFilledFieldIds, manuallyFilledDatasetIds,
                                 detectedFieldIds, detectedFieldClassifications,
-                                saveDialogNotShowReason, uiType));
+                                saveDialogNotShowReason, uiType, focusedId));
                     }
                     return selection;
                 }
diff --git a/core/java/android/service/notification/SystemZenRules.java b/core/java/android/service/notification/SystemZenRules.java
index ebb8569..f11ce16 100644
--- a/core/java/android/service/notification/SystemZenRules.java
+++ b/core/java/android/service/notification/SystemZenRules.java
@@ -122,17 +122,16 @@
     @Nullable
     public static String getTriggerDescriptionForScheduleTime(Context context,
             @NonNull ScheduleInfo schedule) {
-        final StringBuilder sb = new StringBuilder();
         String daysSummary = getDaysOfWeekShort(context, schedule);
         if (daysSummary == null) {
             // no use outputting times without dates
             return null;
         }
-        sb.append(daysSummary);
-        sb.append(context.getString(R.string.zen_mode_trigger_summary_divider_text));
-        sb.append(getTimeSummary(context, schedule));
-
-        return sb.toString();
+        return context.getString(
+                R.string.zen_mode_trigger_summary_combined,
+                daysSummary,
+                getTimeSummary(context, schedule)
+        );
     }
 
     /**
diff --git a/core/java/android/service/quickaccesswallet/flags.aconfig b/core/java/android/service/quickaccesswallet/flags.aconfig
index 75a9309..7225f27 100644
--- a/core/java/android/service/quickaccesswallet/flags.aconfig
+++ b/core/java/android/service/quickaccesswallet/flags.aconfig
@@ -6,4 +6,11 @@
     namespace: "wallet_integration"
     description: "Option to launch the Wallet app on double-tap of the power button"
     bug: "378469025"
+}
+
+flag {
+    name: "launch_selected_card_from_qs_tile"
+    namespace: "wallet_integration"
+    description: "When the wallet QS tile is tapped, launch the selected card pending intent instead of the home screen pending intent."
+    bug: "378469025"
 }
\ No newline at end of file
diff --git a/core/java/android/service/wearable/WearableSensingService.java b/core/java/android/service/wearable/WearableSensingService.java
index 47ec080..e20d5e9 100644
--- a/core/java/android/service/wearable/WearableSensingService.java
+++ b/core/java/android/service/wearable/WearableSensingService.java
@@ -27,6 +27,7 @@
 import android.app.ambientcontext.AmbientContextEventRequest;
 import android.app.wearable.Flags;
 import android.app.wearable.IWearableSensingCallback;
+import android.app.wearable.WearableConnection;
 import android.app.wearable.WearableSensingDataRequest;
 import android.app.wearable.WearableSensingManager;
 import android.content.Context;
@@ -380,7 +381,11 @@
      *
      * @param secureWearableConnection The secure connection to the wearable.
      * @param statusConsumer The consumer for the service status.
+     * @deprecated Use {@link #onSecureConnectionProvided(ParcelFileDescriptor, PersistableBundle,
+     *     Consumer)} instead to receive a remote wearable device connection.
      */
+    @FlaggedApi(Flags.FLAG_ENABLE_CONCURRENT_WEARABLE_CONNECTIONS)
+    @Deprecated
     @BinderThread
     public void onSecureConnectionProvided(
             @NonNull ParcelFileDescriptor secureWearableConnection,
@@ -389,12 +394,20 @@
     }
 
     /**
-     * Called when a secure connection to the wearable is available.
+     * Called when a secure connection to the wearable is available. See {@link
+     * WearableSensingManager#provideConnection(WearableConnection, Executor)} for details about the
+     * secure connection.
+     *
+     * <p>When the {@code secureWearableConnection} is closed, the system will send a {@link
+     * WearableSensingManager#STATUS_CHANNEL_ERROR} status code to the error callback provided by
+     * the caller of {@link WearableSensingManager#provideConnection(WearableConnection, Executor)}.
+     *
+     * <p>The implementing class should override this method. It should return an appropriate status
+     * code via {@code statusConsumer} after receiving the {@code secureWearableConnection}.
      *
      * @param secureWearableConnection The secure connection to the wearable.
      * @param metadata Metadata related to the provided connection.
      * @param statusConsumer The consumer for the service status.
-     * @see #onSecureConnectionProvided(ParcelFileDescriptor, Consumer)
      */
     @FlaggedApi(Flags.FLAG_ENABLE_CONCURRENT_WEARABLE_CONNECTIONS)
     @BinderThread
diff --git a/core/java/android/text/style/TtsSpan.java b/core/java/android/text/style/TtsSpan.java
index e0d4ec1..a337ba2 100644
--- a/core/java/android/text/style/TtsSpan.java
+++ b/core/java/android/text/style/TtsSpan.java
@@ -108,13 +108,11 @@
 
     /**
      * The text associated with this span is a time, consisting of a number of
-     * hours, minutes, and seconds specified with {@link #ARG_HOURS}, {@link #ARG_MINUTES}, and
-     * {@link #ARG_SECONDS}.
+     * hours and minutes, specified with {@link #ARG_HOURS} and
+     * {@link #ARG_MINUTES}.
      * Also accepts the arguments {@link #ARG_GENDER},
      * {@link #ARG_ANIMACY}, {@link #ARG_MULTIPLICITY} and
-     * {@link #ARG_CASE}. This is different from {@link #TYPE_DURATION}. This should be used to
-     * convey a particular moment in time, such as a clock time, while {@link #TYPE_DURATION} should
-     * be used to convey an interval of time.
+     * {@link #ARG_CASE}.
      */
     public static final String TYPE_TIME = "android.type.time";
 
@@ -312,18 +310,16 @@
     public static final String ARG_UNIT = "android.arg.unit";
 
     /**
-     * Argument used to specify the hours of a time or duration. The hours should be
-     * provided as an integer in the range from 0 up to and including 24 for
-     * {@link #TYPE_TIME}.
-     * Can be used with {@link #TYPE_TIME} or {@link #TYPE_DURATION}.
+     * Argument used to specify the hours of a time. The hours should be
+     * provided as an integer in the range from 0 up to and including 24.
+     * Can be used with {@link #TYPE_TIME}.
      */
     public static final String ARG_HOURS = "android.arg.hours";
 
     /**
-     * Argument used to specify the minutes of a time or duration. The minutes should be
-     * provided as an integer in the range from 0 up to and including 59 for
-     * {@link #TYPE_TIME}.
-     * Can be used with {@link #TYPE_TIME} or {@link #TYPE_DURATION}.
+     * Argument used to specify the minutes of a time. The minutes should be
+     * provided as an integer in the range from 0 up to and including 59.
+     * Can be used with {@link #TYPE_TIME}.
      */
     public static final String ARG_MINUTES = "android.arg.minutes";
 
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index 1dd9d46..f8737a5 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -75,7 +75,7 @@
 @android.ravenwood.annotation.RavenwoodClassLoadHook(
         "com.android.platform.test.ravenwood.runtimehelper.ClassLoadHook.onClassLoaded")
 // Uncomment the following annotation to switch to the Java substitution version.
-@android.ravenwood.annotation.RavenwoodRedirectionClass("Log_host")
+@android.ravenwood.annotation.RavenwoodRedirectionClass("Log_ravenwood")
 public final class Log {
     /** @hide */
     @IntDef({ASSERT, ERROR, WARN, INFO, DEBUG, VERBOSE})
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index a1a9fc6..c9d560c 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -20,6 +20,7 @@
 import static android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS;
 import static android.hardware.flags.Flags.FLAG_OVERLAYPROPERTIES_CLASS_API;
 
+import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_GET_SUPPORTED_REFRESH_RATES;
 import static com.android.server.display.feature.flags.Flags.FLAG_HIGHEST_HDR_SDR_RATIO_API;
 import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_HAS_ARR_SUPPORT;
 import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_GET_SUGGESTED_FRAME_RATE;
@@ -63,6 +64,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
@@ -1207,17 +1209,36 @@
 
     /**
      * Get the supported refresh rates of this display in frames per second.
-     * <p>
-     * This method only returns refresh rates for the display's default modes. For more options, use
-     * {@link #getSupportedModes()}.
      *
-     * @deprecated use {@link #getSupportedModes()} instead
+     * <ul>
+     * <li> Android version {@link Build.VERSION_CODES#BAKLAVA} and above:
+     * returns display supported render rates.
+     * <li> Android version {@link Build.VERSION_CODES#VANILLA_ICE_CREAM} and below:
+     * This method only returns refresh rates for the display's default modes. For more options,
+     * use {@link #getSupportedModes()}.
+     * </ul>
      */
-    @Deprecated
-    public float[] getSupportedRefreshRates() {
+    @FlaggedApi(FLAG_ENABLE_GET_SUPPORTED_REFRESH_RATES)
+    public @NonNull float[] getSupportedRefreshRates() {
         synchronized (mLock) {
             updateDisplayInfoLocked();
-            return mDisplayInfo.getDefaultRefreshRates();
+            final float[] refreshRates = mDisplayInfo.getDefaultRefreshRates();
+            Objects.requireNonNull(refreshRates);
+            return refreshRates;
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @TestApi
+    @SuppressLint({"UnflaggedApi"}) // Usage in the CTS to test backward compatibility.
+    public @NonNull float[] getSupportedRefreshRatesLegacy() {
+        synchronized (mLock) {
+            updateDisplayInfoLocked();
+            final float[] refreshRates = mDisplayInfo.getDefaultRefreshRatesLegacy();
+            Objects.requireNonNull(refreshRates);
+            return refreshRates;
         }
     }
 
@@ -1279,8 +1300,19 @@
         }
     }
 
+    /**
+     * Represents the {@link FrameRateCategory} for the Normal frame rate
+     *
+     * @see FrameRateCategory
+     */
     @FlaggedApi(FLAG_ENABLE_GET_SUGGESTED_FRAME_RATE)
     public static final int FRAME_RATE_CATEGORY_NORMAL = 0;
+
+    /**
+     * Represents the {@link FrameRateCategory} for the High frame rate
+     *
+     * @see FrameRateCategory
+     */
     @FlaggedApi(FLAG_ENABLE_GET_SUGGESTED_FRAME_RATE)
     public static final int FRAME_RATE_CATEGORY_HIGH = 1;
 
@@ -2438,6 +2470,8 @@
          * constrained by the system.
          * @hide
          */
+        @SuppressWarnings("UnflaggedApi") // For testing only
+        @TestApi
         public float getVsyncRate() {
             return mVsyncRate;
         }
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 4ff04d5..8b6458a 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -210,6 +210,11 @@
     public FrameRateCategoryRate frameRateCategoryRate;
 
     /**
+     * All the refresh rates supported in the active mode.
+     */
+    public float[] supportedRefreshRates = new float[0];
+
+    /**
      * The default display mode.
      */
     public int defaultModeId;
@@ -449,6 +454,7 @@
                 && modeId == other.modeId
                 && hasArrSupport == other.hasArrSupport
                 && Objects.equals(frameRateCategoryRate, other.frameRateCategoryRate)
+                && Arrays.equals(supportedRefreshRates, other.supportedRefreshRates)
                 && defaultModeId == other.defaultModeId
                 && userPreferredModeId == other.userPreferredModeId
                 && Arrays.equals(supportedModes, other.supportedModes)
@@ -512,6 +518,8 @@
         renderFrameRate = other.renderFrameRate;
         hasArrSupport = other.hasArrSupport;
         frameRateCategoryRate = other.frameRateCategoryRate;
+        supportedRefreshRates = Arrays.copyOf(
+                other.supportedRefreshRates, other.supportedRefreshRates.length);
         defaultModeId = other.defaultModeId;
         userPreferredModeId = other.userPreferredModeId;
         supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length);
@@ -571,6 +579,11 @@
         hasArrSupport = source.readBoolean();
         frameRateCategoryRate = source.readParcelable(null,
                 android.view.FrameRateCategoryRate.class);
+        int numOfSupportedRefreshRates = source.readInt();
+        supportedRefreshRates = new float[numOfSupportedRefreshRates];
+        for (int i = 0; i < numOfSupportedRefreshRates; i++) {
+            supportedRefreshRates[i] = source.readFloat();
+        }
         defaultModeId = source.readInt();
         userPreferredModeId = source.readInt();
         int nModes = source.readInt();
@@ -646,6 +659,10 @@
         dest.writeFloat(renderFrameRate);
         dest.writeBoolean(hasArrSupport);
         dest.writeParcelable(frameRateCategoryRate, flags);
+        dest.writeInt(supportedRefreshRates.length);
+        for (float supportedRefreshRate : supportedRefreshRates) {
+            dest.writeFloat(supportedRefreshRate);
+        }
         dest.writeInt(defaultModeId);
         dest.writeInt(userPreferredModeId);
         dest.writeInt(supportedModes.length);
@@ -750,9 +767,19 @@
     }
 
     /**
-     * Returns the list of supported refresh rates in the default mode.
+     * Returns the list of supported refresh rates in the active mode.
      */
     public float[] getDefaultRefreshRates() {
+        if (supportedRefreshRates.length == 0) {
+            return getDefaultRefreshRatesLegacy();
+        }
+        return Arrays.copyOf(supportedRefreshRates, supportedRefreshRates.length);
+    }
+
+    /**
+     * Returns the list of supported refresh rates in the default mode.
+     */
+    public float[] getDefaultRefreshRatesLegacy() {
         Display.Mode[] modes = appsSupportedModes;
         ArraySet<Float> rates = new ArraySet<>();
         Display.Mode defaultMode = getDefaultMode();
@@ -898,6 +925,8 @@
         sb.append(hasArrSupport);
         sb.append(", frameRateCategoryRate ");
         sb.append(frameRateCategoryRate);
+        sb.append(", supportedRefreshRates ");
+        sb.append(Arrays.toString(supportedRefreshRates));
         sb.append(", defaultMode ");
         sb.append(defaultModeId);
         sb.append(", userPreferredModeId ");
diff --git a/core/java/android/view/IDisplayWindowInsetsController.aidl b/core/java/android/view/IDisplayWindowInsetsController.aidl
index 45dbe43..21b969c 100644
--- a/core/java/android/view/IDisplayWindowInsetsController.aidl
+++ b/core/java/android/view/IDisplayWindowInsetsController.aidl
@@ -60,5 +60,5 @@
      * Reports the requested IME visibility of the IME input target to
      * the IDisplayWindowInsetsController
      */
-    void setImeInputTargetRequestedVisibility(boolean visible);
+    void setImeInputTargetRequestedVisibility(boolean visible, in ImeTracker.Token statsToken);
 }
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index e5be531..6d85e75 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -62,6 +62,7 @@
 import android.view.InputChannel;
 import android.view.InputDevice;
 import android.view.IInputFilter;
+import android.view.inputmethod.ImeTracker;
 import android.view.AppTransitionAnimationSpec;
 import android.view.WindowContentFrameStats;
 import android.view.WindowManager;
@@ -765,7 +766,8 @@
      * container.
      */
     @EnforcePermission("MANAGE_APP_TOKENS")
-    void updateDisplayWindowRequestedVisibleTypes(int displayId, int requestedVisibleTypes);
+    void updateDisplayWindowRequestedVisibleTypes(int displayId, int requestedVisibleTypes,
+            in @nullable ImeTracker.Token statsToken);
 
     /**
      * Called to get the expected window insets.
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index 58ef5ef..6cd4a40 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -260,6 +260,15 @@
         touchableRegionSurfaceControl = new WeakReference<>(bounds);
     }
 
+    /**
+     * Resize the window touchable region.
+     * @param rect new touchable region rectangle.
+     */
+    public void setTouchableRegion(Rect rect) {
+        touchableRegion.set(rect);
+    }
+
+
     public void setWindowToken(IBinder iwindow) {
         windowToken = iwindow;
     }
diff --git a/core/java/android/view/ScrollCaptureSearchResults.java b/core/java/android/view/ScrollCaptureSearchResults.java
index 3469b9d..b1ce949 100644
--- a/core/java/android/view/ScrollCaptureSearchResults.java
+++ b/core/java/android/view/ScrollCaptureSearchResults.java
@@ -16,10 +16,16 @@
 
 package android.view;
 
+import static android.view.flags.Flags.scrollCaptureTargetZOrderFix;
+
+import static java.util.Comparator.comparing;
 import static java.util.Objects.requireNonNull;
+import static java.util.Objects.requireNonNullElse;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UiThread;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.CancellationSignal;
 import android.util.IndentingPrintWriter;
@@ -113,7 +119,9 @@
 
     private void signalComplete() {
         mComplete = true;
-        mTargets.sort(PRIORITY_ORDER);
+        if (!scrollCaptureTargetZOrderFix()) {
+            mTargets.sort(PRIORITY_ORDER);
+        }
         if (mOnCompleteListener != null) {
             mOnCompleteListener.run();
             mOnCompleteListener = null;
@@ -125,14 +133,73 @@
         return new ArrayList<>(mTargets);
     }
 
+    private Rect getScrollBoundsInWindow(@Nullable ScrollCaptureTarget target) {
+        if (target == null || target.getScrollBounds() == null) {
+            return new Rect();
+        }
+        Rect windowRect = new Rect(target.getScrollBounds());
+        Point windowPosition = target.getPositionInWindow();
+        windowRect.offset(windowPosition.x, windowPosition.y);
+        return windowRect;
+    }
+
     /**
      * Get the top ranked result out of all completed requests.
      *
      * @return the top ranked result
      */
+    @Nullable
     public ScrollCaptureTarget getTopResult() {
-        ScrollCaptureTarget target = mTargets.isEmpty() ? null : mTargets.get(0);
-        return target != null && target.getScrollBounds() != null ? target : null;
+        if (!scrollCaptureTargetZOrderFix()) {
+            ScrollCaptureTarget target = mTargets.isEmpty() ? null : mTargets.get(0);
+            return target != null && target.getScrollBounds() != null ? target : null;
+        }
+        List<ScrollCaptureTarget> filtered = new ArrayList<>();
+
+        mTargets.removeIf(a -> nullOrEmpty(a.getScrollBounds()));
+
+        // Remove scroll targets obscured or covered by other scrolling views.
+        nextTarget:
+        for (int i = 0; i <  mTargets.size(); i++) {
+            ScrollCaptureTarget current = mTargets.get(i);
+
+            View currentView = current.getContainingView();
+
+            // Nested scroll containers:
+            // Check if the next view is a child of the current. If so, skip the current.
+            if (i + 1 < mTargets.size()) {
+                ScrollCaptureTarget next = mTargets.get(i + 1);
+                View nextView = next.getContainingView();
+                // Honor explicit include hint on parent as escape hatch (unless both have it)
+                if (isDescendant(currentView, nextView)
+                        && (!hasIncludeHint(currentView) || hasIncludeHint(nextView))) {
+                    continue;
+                }
+            }
+
+            // Check if any views will be drawn partially or fully over this one.
+            for (int j = i + 1; j < mTargets.size(); j++) {
+                ScrollCaptureTarget above = mTargets.get(j);
+                if (Rect.intersects(getScrollBoundsInWindow(current),
+                        getScrollBoundsInWindow(above))) {
+                    continue nextTarget;
+                }
+            }
+
+            filtered.add(current);
+        }
+
+        // natural order, false->true
+        Comparator<ScrollCaptureTarget> byIncludeHintPresence = comparing(
+                ScrollCaptureSearchResults::hasIncludeHint);
+
+        // natural order, smallest->largest area
+        Comparator<ScrollCaptureTarget> byArea = comparing(
+                target -> area(requireNonNullElse(target.getScrollBounds(), new Rect())));
+
+        // The top result is the last one (with include hint if present, then by largest area)
+        filtered.sort(byIncludeHintPresence.thenComparing(byArea));
+        return filtered.isEmpty() ? null : filtered.getLast();
     }
 
     private class SearchRequest implements Consumer<Rect> {
@@ -226,6 +293,10 @@
         return r == null || r.isEmpty();
     }
 
+    private static boolean hasIncludeHint(ScrollCaptureTarget target) {
+        return hasIncludeHint(target.getContainingView());
+    }
+
     private static boolean hasIncludeHint(View view) {
         return (view.getScrollCaptureHint() & View.SCROLL_CAPTURE_HINT_INCLUDE) != 0;
     }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 68674dd..dd9a95e 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -1932,6 +1932,7 @@
         public float renderFrameRate;
         public boolean hasArrSupport;
         public FrameRateCategoryRate frameRateCategoryRate;
+        public float[] supportedRefreshRates;
 
         public int[] supportedColorModes;
         public int activeColorMode;
@@ -1951,6 +1952,7 @@
                     + ", renderFrameRate=" + renderFrameRate
                     + ", hasArrSupport=" + hasArrSupport
                     + ", frameRateCategoryRate=" + frameRateCategoryRate
+                    + ", supportedRefreshRates=" + Arrays.toString(supportedRefreshRates)
                     + ", supportedColorModes=" + Arrays.toString(supportedColorModes)
                     + ", activeColorMode=" + activeColorMode
                     + ", hdrCapabilities=" + hdrCapabilities
@@ -1972,14 +1974,15 @@
                 && Objects.equals(hdrCapabilities, that.hdrCapabilities)
                 && preferredBootDisplayMode == that.preferredBootDisplayMode
                 && hasArrSupport == that.hasArrSupport
-                && Objects.equals(frameRateCategoryRate, that.frameRateCategoryRate);
+                && Objects.equals(frameRateCategoryRate, that.frameRateCategoryRate)
+                && Arrays.equals(supportedRefreshRates, that.supportedRefreshRates);
         }
 
         @Override
         public int hashCode() {
             return Objects.hash(Arrays.hashCode(supportedDisplayModes), activeDisplayModeId,
                     renderFrameRate, activeColorMode, hdrCapabilities, hasArrSupport,
-                    frameRateCategoryRate);
+                    frameRateCategoryRate, Arrays.hashCode(supportedRefreshRates));
         }
     }
 
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 4df7649..b0051ce 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -932,7 +932,8 @@
 
     /**
      * Sets the desired amount of HDR headroom to be used when HDR content is presented on this
-     * SurfaceView.
+     * SurfaceView. This is expressed as the ratio of maximum HDR white point over the SDR
+     * white point, not as absolute nits.
      *
      * <p>By default the system will choose an amount of HDR headroom that is appropriate
      * for the underlying device capabilities & bit-depth of the panel. However, for some types
@@ -946,6 +947,10 @@
      * See {@link Display#getHdrSdrRatio()} for more information as well as how to query the
      * current value.</p>
      *
+     * <p>Note: This API operates independently of both the
+     * {@link Window#setColorMode Widow color mode} and the
+     * {@link Window#setDesiredHdrHeadroom Window desiredHdrHeadroom}</p>
+     *
      * @param desiredHeadroom The amount of HDR headroom that is desired. Must be >= 1.0 (no HDR)
      *                        and <= 10,000.0. Passing 0.0 will reset to the default, automatically
      *                        chosen value.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4a9916c..949b667 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -20,6 +20,7 @@
 import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
 import static android.view.flags.Flags.FLAG_TOOLKIT_VIEWGROUP_SET_REQUESTED_FRAME_RATE_API;
 import static android.view.flags.Flags.toolkitViewgroupSetRequestedFrameRateApi;
+import static android.view.flags.Flags.scrollCaptureTargetZOrderFix;
 
 import android.animation.LayoutTransition;
 import android.annotation.CallSuper;
@@ -7657,6 +7658,11 @@
             @NonNull Rect localVisibleRect, @NonNull Point windowOffset,
             @NonNull Consumer<ScrollCaptureTarget> targets) {
 
+        // Only visible views can be captured.
+        if (getVisibility() != View.VISIBLE) {
+            return;
+        }
+
         if (getClipToPadding() && !localVisibleRect.intersect(mPaddingLeft, mPaddingTop,
                     (mRight - mLeft)  - mPaddingRight, (mBottom - mTop) - mPaddingBottom)) {
             return;
@@ -7665,19 +7671,39 @@
         // Dispatch to self first.
         super.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, targets);
 
+        final int childrenCount = mChildrenCount;
+        if (childrenCount == 0) {
+            return;
+        }
+
         // Skip children if descendants excluded.
         if ((getScrollCaptureHint() & SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS) != 0) {
             return;
         }
-
         final Rect tmpRect = getTempRect();
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
+
+        ArrayList<View> preorderedList = null;
+        boolean customOrder = false;
+        if (scrollCaptureTargetZOrderFix()) {
+            preorderedList = buildOrderedChildList();
+            customOrder = preorderedList == null && isChildrenDrawingOrderEnabled();
+        }
+        final View[] children = mChildren;
+        for (int i = 0; i < childrenCount; i++) {
+            View child;
+            if (scrollCaptureTargetZOrderFix()) {
+                // Traverse children in the same order they will be drawn (honors Z if set)
+                final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
+                child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
+            } else {
+                child = children[i];
+            }
+
             // Only visible views can be captured.
             if (child.getVisibility() != View.VISIBLE) {
                 continue;
             }
+
             // Offset the given rectangle (in parent's local coordinates) into child's coordinate
             // space and clip the result to the child View's bounds, padding and clipRect as needed.
             // If the resulting rectangle is not empty, the request is forwarded to the child.
@@ -7706,6 +7732,9 @@
                 child.dispatchScrollCaptureSearch(tmpRect, childWindowOffset, targets);
             }
         }
+        if (preorderedList != null) {
+            preorderedList.clear();
+        }
     }
 
     /**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 072a835..a0feccd 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1236,6 +1236,8 @@
     private @ActivityInfo.ColorMode int mCurrentColorMode = ActivityInfo.COLOR_MODE_DEFAULT;
     private long mColorModeLastSetMillis = -1;
 
+    private final boolean mIsSubscribeGranularDisplayEventsEnabled;
+
     public ViewRootImpl(Context context, Display display) {
         this(context, display, WindowManagerGlobal.getWindowSession(), new WindowLayout());
     }
@@ -1333,6 +1335,8 @@
         // Disable DRAW_WAKE_LOCK starting U.
         mDisableDrawWakeLock =
                 CompatChanges.isChangeEnabled(DISABLE_DRAW_WAKE_LOCK) && disableDrawWakeLock();
+        mIsSubscribeGranularDisplayEventsEnabled =
+                com.android.server.display.feature.flags.Flags.subscribeGranularDisplayEvents();
     }
 
     public static void addFirstDrawHandler(Runnable callback) {
@@ -1810,14 +1814,22 @@
                 mAccessibilityInteractionConnectionManager, mHandler);
         mAccessibilityManager.addHighContrastTextStateChangeListener(
                 mExecutor, mHighContrastTextManager);
+
+
+        long eventsToBeRegistered =
+                (mIsSubscribeGranularDisplayEventsEnabled)
+                ? DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED
+                        | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_STATE
+                        | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED
+                : DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED
+                        | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED
+                        | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED;
         DisplayManagerGlobal
                 .getInstance()
                 .registerDisplayListener(
                         mDisplayListener,
                         mHandler,
-                        DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED
-                        | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED
-                        | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED,
+                        eventsToBeRegistered,
                         mBasePackageName);
 
         if (forceInvertColor()) {
@@ -8876,11 +8888,6 @@
 
         SyntheticTouchNavigationHandler() {
             super(true);
-            int gestureDetectorVelocityStrategy =
-                    android.companion.virtual.flags.Flags
-                            .impulseVelocityStrategyForTouchNavigation()
-                    ? VelocityTracker.VELOCITY_TRACKER_STRATEGY_IMPULSE
-                    : VelocityTracker.VELOCITY_TRACKER_STRATEGY_DEFAULT;
             mGestureDetector = new GestureDetector(mContext,
                     new GestureDetector.OnGestureListener() {
                         @Override
@@ -8920,7 +8927,7 @@
                         }
                     },
                     /* handler= */ null,
-                    gestureDetectorVelocityStrategy);
+                    VelocityTracker.VELOCITY_TRACKER_STRATEGY_IMPULSE);
         }
 
         public void process(MotionEvent event) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 381006c..3953334 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1334,6 +1334,9 @@
      * <p>The requested color mode is not guaranteed to be honored. Please refer to
      * {@link #getColorMode()} for more information.</p>
      *
+     * <p>Note: This does not impact SurfaceViews or SurfaceControls, as those have their own
+     * independent color mode and HDR parameters.</p>
+     *
      * @see #getColorMode()
      * @see Display#isWideColorGamut()
      * @see Configuration#isScreenWideColorGamut()
@@ -1361,6 +1364,9 @@
      * See {@link Display#getHdrSdrRatio()} for more information as well as how to query the
      * current value.</p>
      *
+     * <p>Note: This does not impact SurfaceViews or SurfaceControls, as those have their own
+     * independent desired HDR headroom and HDR capabilities.</p>
+     *
      * @param desiredHeadroom The amount of HDR headroom that is desired. Must be >= 1.0 (no HDR)
      *                        and <= 10,000.0. Passing 0.0 will reset to the default, automatically
      *                        chosen value.
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index b4b0687..1e8cad6 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1426,8 +1426,9 @@
             "android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE";
 
     /**
-     * Activity-level {@link android.content.pm.PackageManager.Property PackageManager.Property}
-     * that specifies whether this activity can declare or request
+     * Application or Activity level
+     * {@link android.content.pm.PackageManager.Property PackageManager.Property}
+     * that specifies whether this package or activity can declare or request
      * {@link android.R.attr#screenOrientation fixed orientation},
      * {@link android.R.attr#minAspectRatio max aspect ratio},
      * {@link android.R.attr#maxAspectRatio min aspect ratio}
@@ -1438,6 +1439,13 @@
      *
      * <p><b>Syntax:</b>
      * <pre>
+     * &lt;application&gt;
+     *   &lt;property
+     *     android:name="android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE"
+     *     android:value="false"/&gt;
+     * &lt;/application&gt;
+     * </pre>or
+     * <pre>
      * &lt;activity&gt;
      *   &lt;property
      *     android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY"
@@ -1446,7 +1454,7 @@
      * </pre>
      * @hide
      */
-    // TODO(b/357141415): Make this public API.
+    // TODO(b/357141415): Remove this from sdk 37
     String PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY =
             "android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY";
 
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 0dfaf41..88ccf88 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -959,6 +959,8 @@
                 CONTENT_CHANGE_TYPE_CONTENT_INVALID,
                 CONTENT_CHANGE_TYPE_ERROR,
                 CONTENT_CHANGE_TYPE_ENABLED,
+                CONTENT_CHANGE_TYPE_CHECKED,
+                CONTENT_CHANGE_TYPE_EXPANDED,
                 CONTENT_CHANGE_TYPE_SUPPLEMENTAL_DESCRIPTION,
             })
     public @interface ContentChangeTypes {}
@@ -1241,6 +1243,16 @@
             case CONTENT_CHANGE_TYPE_ERROR: return "CONTENT_CHANGE_TYPE_ERROR";
             case CONTENT_CHANGE_TYPE_ENABLED: return "CONTENT_CHANGE_TYPE_ENABLED";
             default: {
+                if (Flags.triStateChecked()) {
+                    if (type == CONTENT_CHANGE_TYPE_CHECKED) {
+                        return "CONTENT_CHANGE_TYPE_CHECKED";
+                    }
+                }
+                if (Flags.a11yExpansionStateApi()) {
+                    if (type == CONTENT_CHANGE_TYPE_EXPANDED) {
+                        return "CONTENT_CHANGE_TYPE_EXPANDED";
+                    }
+                }
                 if (Flags.supplementalDescription()) {
                     if (type == CONTENT_CHANGE_TYPE_SUPPLEMENTAL_DESCRIPTION) {
                         return "CONTENT_CHANGE_TYPE_SUPPLEMENTAL_DESCRIPTION";
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 0204517..df0c5a3 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -6551,16 +6551,24 @@
         /**
          * Range type: indeterminate.
          *
-         * A {@link RangeInfo} type used to represent a node which may typically expose range
-         * information but is presently in an indeterminate state, such as a {@link
-         * android.widget.ProgressBar} representing a loading operation of unknown duration.
          * When using this type, the {@code min}, {@code max}, and {@code current} values used to
-         * construct an instance may be ignored. It is recommended to use {@code Float.NaN} for
-         * these values.
+         * construct an instance may be ignored.
+         *
+         *  @see #INDETERMINATE
          */
         @FlaggedApi(Flags.FLAG_INDETERMINATE_RANGE_INFO)
         public static final int RANGE_TYPE_INDETERMINATE = 3;
 
+        /**
+         * A {@link RangeInfo} type used to represent a node which may typically expose range
+         * information but is presently in an indeterminate state, such as a {@link
+         * android.widget.ProgressBar} representing a loading operation of unknown duration.
+         */
+        @NonNull
+        @FlaggedApi(Flags.FLAG_INDETERMINATE_RANGE_INFO)
+        public static final RangeInfo INDETERMINATE = new RangeInfo(RANGE_TYPE_INDETERMINATE, 0.0f,
+                0.0f, 0.0f);
+
         private int mType;
         private float mMin;
         private float mMax;
diff --git a/core/java/android/view/flags/scroll_capture.aconfig b/core/java/android/view/flags/scroll_capture.aconfig
new file mode 100644
index 0000000..fdf9c1e
--- /dev/null
+++ b/core/java/android/view/flags/scroll_capture.aconfig
@@ -0,0 +1,13 @@
+package: "android.view.flags"
+container: "system"
+
+flag {
+    name: "scroll_capture_target_z_order_fix"
+    namespace: "system_ui"
+    description: "Always prefer targets with higher z-order"
+    bug: "365969802"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
diff --git a/core/java/android/view/inputmethod/ImeTracker.java b/core/java/android/view/inputmethod/ImeTracker.java
index dd32d57..4d354e0 100644
--- a/core/java/android/view/inputmethod/ImeTracker.java
+++ b/core/java/android/view/inputmethod/ImeTracker.java
@@ -222,6 +222,8 @@
             PHASE_CLIENT_ALREADY_HIDDEN,
             PHASE_CLIENT_VIEW_HANDLER_AVAILABLE,
             PHASE_SERVER_UPDATE_CLIENT_VISIBILITY,
+            PHASE_WM_DISPLAY_IME_CONTROLLER_SET_IME_REQUESTED_VISIBLE,
+            PHASE_WM_UPDATE_DISPLAY_WINDOW_REQUESTED_VISIBLE_TYPES,
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface Phase {}
@@ -436,6 +438,12 @@
      * app or the RemoteInsetsControlTarget).
      */
     int PHASE_SERVER_UPDATE_CLIENT_VISIBILITY = ImeProtoEnums.PHASE_SERVER_UPDATE_CLIENT_VISIBILITY;
+    /** DisplayImeController received the requested visibility for the IME and stored it. */
+    int PHASE_WM_DISPLAY_IME_CONTROLLER_SET_IME_REQUESTED_VISIBLE =
+            ImeProtoEnums.PHASE_WM_DISPLAY_IME_CONTROLLER_SET_IME_REQUESTED_VISIBLE;
+    /** The control target reported its requestedVisibleTypes back to WindowManagerService. */
+    int PHASE_WM_UPDATE_DISPLAY_WINDOW_REQUESTED_VISIBLE_TYPES =
+            ImeProtoEnums.PHASE_WM_UPDATE_DISPLAY_WINDOW_REQUESTED_VISIBLE_TYPES;
 
     /**
      * Called when an IME request is started.
diff --git a/core/java/android/widget/Button.java b/core/java/android/widget/Button.java
index 0bf6380..eb3b768 100644
--- a/core/java/android/widget/Button.java
+++ b/core/java/android/widget/Button.java
@@ -134,6 +134,7 @@
         // 1. app target sdk is 36 or above.
         // 2. feature flag rolled-out.
         // 3. device is a watch.
+        // 4. button uses Theme.DeviceDefault.
         // getButtonDefaultStyleAttr and getButtonDefaultStyleRes works together to alter the UI
         // while considering the conditions above.
         // Their results are mutual exclusive. i.e. when conditions above are all true,
@@ -229,6 +230,7 @@
 
     private static boolean useWearMaterial3Style(Context context) {
         return Flags.useWearMaterial3Ui() && CompatChanges.isChangeEnabled(WEAR_MATERIAL3_BUTTON)
-                && context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+                && context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)
+                && context.getThemeResId() == com.android.internal.R.style.Theme_DeviceDefault;
     }
 }
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 6e43d0f..2a8a928 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -16,6 +16,8 @@
 
 package android.widget;
 
+import static android.view.accessibility.Flags.indeterminateRangeInfo;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
@@ -2364,15 +2366,22 @@
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
 
-        if (!isIndeterminate()) {
-            AccessibilityNodeInfo.RangeInfo rangeInfo = AccessibilityNodeInfo.RangeInfo.obtain(
+        AccessibilityNodeInfo.RangeInfo rangeInfo = null;
+        if (isIndeterminate()) {
+            if (indeterminateRangeInfo()) {
+                rangeInfo = AccessibilityNodeInfo.RangeInfo.INDETERMINATE;
+            }
+        }  else {
+            rangeInfo = new AccessibilityNodeInfo.RangeInfo(
                     AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT, getMin(), getMax(),
                     getProgress());
-            info.setRangeInfo(rangeInfo);
         }
 
-        // Only set the default state description when custom state descripton is null.
+        info.setRangeInfo(rangeInfo);
+
+        // Only set the default state description when custom state description is null.
         if (getStateDescription() == null) {
+            // TODO(b/380340432): Remove after accessibility services stop relying on this.
             if (isIndeterminate()) {
                 info.setStateDescription(getResources().getString(R.string.in_progress));
             } else {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index d85f526..7e3b904 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1298,7 +1298,13 @@
 
         @Override
         public void visitUris(@NonNull Consumer<Uri> visitor) {
-            if (mIntentId != -1 || mItems == null) {
+            if (mItems == null) {
+                // Null item indicates adapter conversion took place, so the URIs in cached items
+                // need to be validated.
+                RemoteCollectionItems cachedItems = mCollectionCache.getItemsForId(mIntentId);
+                if (cachedItems != null) {
+                    cachedItems.visitUris(visitor);
+                }
                 return;
             }
 
@@ -8483,8 +8489,11 @@
             }
             try {
                 LoadedApk.checkAndUpdateApkPaths(mApplication);
-                return context.createApplicationContext(mApplication,
+                Context applicationContext = context.createApplicationContext(mApplication,
                         Context.CONTEXT_RESTRICTED);
+                // Get the correct apk paths while maintaining the current context's configuration.
+                return applicationContext.createConfigurationContext(
+                        context.getResources().getConfiguration());
             } catch (NameNotFoundException e) {
                 Log.e(LOG_TAG, "Package name " + mApplication.packageName + " not found");
             }
@@ -9330,7 +9339,11 @@
         Set<Integer> bitmapIdSet = getBitmapIdsUsedByActions(new HashSet<>());
         int result = 0;
         for (int bitmapId: bitmapIdSet) {
-            result += mBitmapCache.getBitmapForId(bitmapId).getAllocationByteCount();
+            Bitmap currentBitmap = mBitmapCache.getBitmapForId(bitmapId);
+            if (currentBitmap == null) {
+                continue;
+            }
+            result += currentBitmap.getAllocationByteCount();
         }
 
         return result;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index cb70466..d7750bd 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -106,7 +106,6 @@
 import android.os.ParcelableParcel;
 import android.os.Process;
 import android.os.SystemClock;
-import android.os.Trace;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.BoringLayout;
@@ -9230,179 +9229,174 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
-        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "TextView.onDraw");
-        try {
-            restartMarqueeIfNeeded();
+        restartMarqueeIfNeeded();
 
-            // Draw the background for this view
-            super.onDraw(canvas);
+        // Draw the background for this view
+        super.onDraw(canvas);
 
-            final int compoundPaddingLeft = getCompoundPaddingLeft();
-            final int compoundPaddingTop = getCompoundPaddingTop();
-            final int compoundPaddingRight = getCompoundPaddingRight();
-            final int compoundPaddingBottom = getCompoundPaddingBottom();
-            final int scrollX = mScrollX;
-            final int scrollY = mScrollY;
-            final int right = mRight;
-            final int left = mLeft;
-            final int bottom = mBottom;
-            final int top = mTop;
-            final boolean isLayoutRtl = isLayoutRtl();
-            final int offset = getHorizontalOffsetForDrawables();
-            final int leftOffset = isLayoutRtl ? 0 : offset;
-            final int rightOffset = isLayoutRtl ? offset : 0;
+        final int compoundPaddingLeft = getCompoundPaddingLeft();
+        final int compoundPaddingTop = getCompoundPaddingTop();
+        final int compoundPaddingRight = getCompoundPaddingRight();
+        final int compoundPaddingBottom = getCompoundPaddingBottom();
+        final int scrollX = mScrollX;
+        final int scrollY = mScrollY;
+        final int right = mRight;
+        final int left = mLeft;
+        final int bottom = mBottom;
+        final int top = mTop;
+        final boolean isLayoutRtl = isLayoutRtl();
+        final int offset = getHorizontalOffsetForDrawables();
+        final int leftOffset = isLayoutRtl ? 0 : offset;
+        final int rightOffset = isLayoutRtl ? offset : 0;
 
-            final Drawables dr = mDrawables;
-            if (dr != null) {
-                /*
-                 * Compound, not extended, because the icon is not clipped
-                 * if the text height is smaller.
-                 */
+        final Drawables dr = mDrawables;
+        if (dr != null) {
+            /*
+             * Compound, not extended, because the icon is not clipped
+             * if the text height is smaller.
+             */
 
-                int vspace = bottom - top - compoundPaddingBottom - compoundPaddingTop;
-                int hspace = right - left - compoundPaddingRight - compoundPaddingLeft;
+            int vspace = bottom - top - compoundPaddingBottom - compoundPaddingTop;
+            int hspace = right - left - compoundPaddingRight - compoundPaddingLeft;
 
-                // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
-                // Make sure to update invalidateDrawable() when changing this code.
-                if (dr.mShowing[Drawables.LEFT] != null) {
-                    canvas.save();
-                    canvas.translate(scrollX + mPaddingLeft + leftOffset,
-                            scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightLeft) / 2);
-                    dr.mShowing[Drawables.LEFT].draw(canvas);
-                    canvas.restore();
-                }
-
-                // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
-                // Make sure to update invalidateDrawable() when changing this code.
-                if (dr.mShowing[Drawables.RIGHT] != null) {
-                    canvas.save();
-                    canvas.translate(scrollX + right - left - mPaddingRight
-                                    - dr.mDrawableSizeRight - rightOffset,
-                            scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightRight) / 2);
-                    dr.mShowing[Drawables.RIGHT].draw(canvas);
-                    canvas.restore();
-                }
-
-                // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
-                // Make sure to update invalidateDrawable() when changing this code.
-                if (dr.mShowing[Drawables.TOP] != null) {
-                    canvas.save();
-                    canvas.translate(scrollX + compoundPaddingLeft
-                            + (hspace - dr.mDrawableWidthTop) / 2, scrollY + mPaddingTop);
-                    dr.mShowing[Drawables.TOP].draw(canvas);
-                    canvas.restore();
-                }
-
-                // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
-                // Make sure to update invalidateDrawable() when changing this code.
-                if (dr.mShowing[Drawables.BOTTOM] != null) {
-                    canvas.save();
-                    canvas.translate(scrollX + compoundPaddingLeft
-                                    + (hspace - dr.mDrawableWidthBottom) / 2,
-                            scrollY + bottom - top - mPaddingBottom - dr.mDrawableSizeBottom);
-                    dr.mShowing[Drawables.BOTTOM].draw(canvas);
-                    canvas.restore();
-                }
+            // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
+            // Make sure to update invalidateDrawable() when changing this code.
+            if (dr.mShowing[Drawables.LEFT] != null) {
+                canvas.save();
+                canvas.translate(scrollX + mPaddingLeft + leftOffset,
+                        scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightLeft) / 2);
+                dr.mShowing[Drawables.LEFT].draw(canvas);
+                canvas.restore();
             }
 
-            int color = mCurTextColor;
-
-            if (mLayout == null) {
-                assumeLayout();
+            // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
+            // Make sure to update invalidateDrawable() when changing this code.
+            if (dr.mShowing[Drawables.RIGHT] != null) {
+                canvas.save();
+                canvas.translate(scrollX + right - left - mPaddingRight
+                        - dr.mDrawableSizeRight - rightOffset,
+                         scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightRight) / 2);
+                dr.mShowing[Drawables.RIGHT].draw(canvas);
+                canvas.restore();
             }
 
-            Layout layout = mLayout;
-
-            if (mHint != null && !mHideHint && mText.length() == 0) {
-                if (mHintTextColor != null) {
-                    color = mCurHintTextColor;
-                }
-
-                layout = mHintLayout;
+            // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
+            // Make sure to update invalidateDrawable() when changing this code.
+            if (dr.mShowing[Drawables.TOP] != null) {
+                canvas.save();
+                canvas.translate(scrollX + compoundPaddingLeft
+                        + (hspace - dr.mDrawableWidthTop) / 2, scrollY + mPaddingTop);
+                dr.mShowing[Drawables.TOP].draw(canvas);
+                canvas.restore();
             }
 
-            mTextPaint.setColor(color);
-            mTextPaint.drawableState = getDrawableState();
-
-            canvas.save();
-            /*  Would be faster if we didn't have to do this. Can we chop the
-                (displayable) text so that we don't need to do this ever?
-            */
-
-            int extendedPaddingTop = getExtendedPaddingTop();
-            int extendedPaddingBottom = getExtendedPaddingBottom();
-
-            final int vspace = mBottom - mTop - compoundPaddingBottom - compoundPaddingTop;
-            final int maxScrollY = mLayout.getHeight() - vspace;
-
-            float clipLeft = compoundPaddingLeft + scrollX;
-            float clipTop = (scrollY == 0) ? 0 : extendedPaddingTop + scrollY;
-            float clipRight = right - left - getCompoundPaddingRight() + scrollX;
-            float clipBottom = bottom - top + scrollY
-                    - ((scrollY == maxScrollY) ? 0 : extendedPaddingBottom);
-
-            if (mShadowRadius != 0) {
-                clipLeft += Math.min(0, mShadowDx - mShadowRadius);
-                clipRight += Math.max(0, mShadowDx + mShadowRadius);
-
-                clipTop += Math.min(0, mShadowDy - mShadowRadius);
-                clipBottom += Math.max(0, mShadowDy + mShadowRadius);
+            // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
+            // Make sure to update invalidateDrawable() when changing this code.
+            if (dr.mShowing[Drawables.BOTTOM] != null) {
+                canvas.save();
+                canvas.translate(scrollX + compoundPaddingLeft
+                        + (hspace - dr.mDrawableWidthBottom) / 2,
+                         scrollY + bottom - top - mPaddingBottom - dr.mDrawableSizeBottom);
+                dr.mShowing[Drawables.BOTTOM].draw(canvas);
+                canvas.restore();
             }
-
-            canvas.clipRect(clipLeft, clipTop, clipRight, clipBottom);
-
-            int voffsetText = 0;
-            int voffsetCursor = 0;
-
-            // translate in by our padding
-            /* shortcircuit calling getVerticaOffset() */
-            if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) {
-                voffsetText = getVerticalOffset(false);
-                voffsetCursor = getVerticalOffset(true);
-            }
-            canvas.translate(compoundPaddingLeft, extendedPaddingTop + voffsetText);
-
-            final int layoutDirection = getLayoutDirection();
-            final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
-            if (isMarqueeFadeEnabled()) {
-                if (!mSingleLine && getLineCount() == 1 && canMarquee()
-                        && (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) {
-                    final int width = mRight - mLeft;
-                    final int padding = getCompoundPaddingLeft() + getCompoundPaddingRight();
-                    final float dx = mLayout.getLineRight(0) - (width - padding);
-                    canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
-                }
-
-                if (mMarquee != null && mMarquee.isRunning()) {
-                    final float dx = -mMarquee.getScroll();
-                    canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
-                }
-            }
-
-            final int cursorOffsetVertical = voffsetCursor - voffsetText;
-
-            maybeUpdateHighlightPaths();
-            // If there is a gesture preview highlight, then the selection or cursor is not drawn.
-            Path highlight = hasGesturePreviewHighlight() ? null : getUpdatedHighlightPath();
-            if (mEditor != null) {
-                mEditor.onDraw(canvas, layout, mHighlightPaths, mHighlightPaints, highlight,
-                        mHighlightPaint, cursorOffsetVertical);
-            } else {
-                layout.draw(canvas, mHighlightPaths, mHighlightPaints, highlight, mHighlightPaint,
-                        cursorOffsetVertical);
-            }
-
-            if (mMarquee != null && mMarquee.shouldDrawGhost()) {
-                final float dx = mMarquee.getGhostOffset();
-                canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
-                layout.draw(canvas, mHighlightPaths, mHighlightPaints, highlight, mHighlightPaint,
-                        cursorOffsetVertical);
-            }
-
-            canvas.restore();
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
         }
+
+        int color = mCurTextColor;
+
+        if (mLayout == null) {
+            assumeLayout();
+        }
+
+        Layout layout = mLayout;
+
+        if (mHint != null && !mHideHint && mText.length() == 0) {
+            if (mHintTextColor != null) {
+                color = mCurHintTextColor;
+            }
+
+            layout = mHintLayout;
+        }
+
+        mTextPaint.setColor(color);
+        mTextPaint.drawableState = getDrawableState();
+
+        canvas.save();
+        /*  Would be faster if we didn't have to do this. Can we chop the
+            (displayable) text so that we don't need to do this ever?
+        */
+
+        int extendedPaddingTop = getExtendedPaddingTop();
+        int extendedPaddingBottom = getExtendedPaddingBottom();
+
+        final int vspace = mBottom - mTop - compoundPaddingBottom - compoundPaddingTop;
+        final int maxScrollY = mLayout.getHeight() - vspace;
+
+        float clipLeft = compoundPaddingLeft + scrollX;
+        float clipTop = (scrollY == 0) ? 0 : extendedPaddingTop + scrollY;
+        float clipRight = right - left - getCompoundPaddingRight() + scrollX;
+        float clipBottom = bottom - top + scrollY
+                - ((scrollY == maxScrollY) ? 0 : extendedPaddingBottom);
+
+        if (mShadowRadius != 0) {
+            clipLeft += Math.min(0, mShadowDx - mShadowRadius);
+            clipRight += Math.max(0, mShadowDx + mShadowRadius);
+
+            clipTop += Math.min(0, mShadowDy - mShadowRadius);
+            clipBottom += Math.max(0, mShadowDy + mShadowRadius);
+        }
+
+        canvas.clipRect(clipLeft, clipTop, clipRight, clipBottom);
+
+        int voffsetText = 0;
+        int voffsetCursor = 0;
+
+        // translate in by our padding
+        /* shortcircuit calling getVerticaOffset() */
+        if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) {
+            voffsetText = getVerticalOffset(false);
+            voffsetCursor = getVerticalOffset(true);
+        }
+        canvas.translate(compoundPaddingLeft, extendedPaddingTop + voffsetText);
+
+        final int layoutDirection = getLayoutDirection();
+        final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
+        if (isMarqueeFadeEnabled()) {
+            if (!mSingleLine && getLineCount() == 1 && canMarquee()
+                    && (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) {
+                final int width = mRight - mLeft;
+                final int padding = getCompoundPaddingLeft() + getCompoundPaddingRight();
+                final float dx = mLayout.getLineRight(0) - (width - padding);
+                canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
+            }
+
+            if (mMarquee != null && mMarquee.isRunning()) {
+                final float dx = -mMarquee.getScroll();
+                canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
+            }
+        }
+
+        final int cursorOffsetVertical = voffsetCursor - voffsetText;
+
+        maybeUpdateHighlightPaths();
+        // If there is a gesture preview highlight, then the selection or cursor is not drawn.
+        Path highlight = hasGesturePreviewHighlight() ? null : getUpdatedHighlightPath();
+        if (mEditor != null) {
+            mEditor.onDraw(canvas, layout, mHighlightPaths, mHighlightPaints, highlight,
+                    mHighlightPaint, cursorOffsetVertical);
+        } else {
+            layout.draw(canvas, mHighlightPaths, mHighlightPaints, highlight, mHighlightPaint,
+                    cursorOffsetVertical);
+        }
+
+        if (mMarquee != null && mMarquee.shouldDrawGhost()) {
+            final float dx = mMarquee.getGhostOffset();
+            canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
+            layout.draw(canvas, mHighlightPaths, mHighlightPaints, highlight, mHighlightPaint,
+                    cursorOffsetVertical);
+        }
+
+        canvas.restore();
     }
 
     @Override
@@ -11260,201 +11254,192 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "TextView.onMeasure");
-        try {
-            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
-            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
-            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
-            int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
 
-            int width;
-            int height;
+        int width;
+        int height;
 
-            BoringLayout.Metrics boring = UNKNOWN_BORING;
-            BoringLayout.Metrics hintBoring = UNKNOWN_BORING;
+        BoringLayout.Metrics boring = UNKNOWN_BORING;
+        BoringLayout.Metrics hintBoring = UNKNOWN_BORING;
 
-            if (mTextDir == null) {
-                mTextDir = getTextDirectionHeuristic();
+        if (mTextDir == null) {
+            mTextDir = getTextDirectionHeuristic();
+        }
+
+        int des = -1;
+        boolean fromexisting = false;
+        final float widthLimit = (widthMode == MeasureSpec.AT_MOST)
+                ?  (float) widthSize : Float.MAX_VALUE;
+
+        if (widthMode == MeasureSpec.EXACTLY) {
+            // Parent has told us how big to be. So be it.
+            width = widthSize;
+        } else {
+            if (mLayout != null && mEllipsize == null) {
+                des = desired(mLayout, mUseBoundsForWidth);
             }
 
-            int des = -1;
-            boolean fromexisting = false;
-            final float widthLimit = (widthMode == MeasureSpec.AT_MOST)
-                    ? (float) widthSize : Float.MAX_VALUE;
-
-            if (widthMode == MeasureSpec.EXACTLY) {
-                // Parent has told us how big to be. So be it.
-                width = widthSize;
+            if (des < 0) {
+                boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir,
+                        isFallbackLineSpacingForBoringLayout(), getResolvedMinimumFontMetrics(),
+                        mBoring);
+                if (boring != null) {
+                    mBoring = boring;
+                }
             } else {
-                if (mLayout != null && mEllipsize == null) {
-                    des = desired(mLayout, mUseBoundsForWidth);
-                }
+                fromexisting = true;
+            }
 
+            if (boring == null || boring == UNKNOWN_BORING) {
                 if (des < 0) {
-                    boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir,
-                            isFallbackLineSpacingForBoringLayout(), getResolvedMinimumFontMetrics(),
-                            mBoring);
-                    if (boring != null) {
-                        mBoring = boring;
-                    }
+                    des = (int) Math.ceil(Layout.getDesiredWidthWithLimit(mTransformed, 0,
+                            mTransformed.length(), mTextPaint, mTextDir, widthLimit,
+                            mUseBoundsForWidth));
+                }
+                width = des;
+            } else {
+                if (mUseBoundsForWidth) {
+                    RectF bbox = boring.getDrawingBoundingBox();
+                    float rightMax = Math.max(bbox.right, boring.width);
+                    float leftMin = Math.min(bbox.left, 0);
+                    width = Math.max(boring.width, (int) Math.ceil(rightMax - leftMin));
                 } else {
-                    fromexisting = true;
+                    width = boring.width;
+                }
+            }
+
+            final Drawables dr = mDrawables;
+            if (dr != null) {
+                width = Math.max(width, dr.mDrawableWidthTop);
+                width = Math.max(width, dr.mDrawableWidthBottom);
+            }
+
+            if (mHint != null) {
+                int hintDes = -1;
+                int hintWidth;
+
+                if (mHintLayout != null && mEllipsize == null) {
+                    hintDes = desired(mHintLayout, mUseBoundsForWidth);
                 }
 
-                if (boring == null || boring == UNKNOWN_BORING) {
-                    if (des < 0) {
-                        des = (int) Math.ceil(Layout.getDesiredWidthWithLimit(mTransformed, 0,
-                                mTransformed.length(), mTextPaint, mTextDir, widthLimit,
+                if (hintDes < 0) {
+                    hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mTextDir,
+                            isFallbackLineSpacingForBoringLayout(), getResolvedMinimumFontMetrics(),
+                            mHintBoring);
+                    if (hintBoring != null) {
+                        mHintBoring = hintBoring;
+                    }
+                }
+
+                if (hintBoring == null || hintBoring == UNKNOWN_BORING) {
+                    if (hintDes < 0) {
+                        hintDes = (int) Math.ceil(Layout.getDesiredWidthWithLimit(mHint, 0,
+                                mHint.length(), mTextPaint, mTextDir, widthLimit,
                                 mUseBoundsForWidth));
                     }
-                    width = des;
+                    hintWidth = hintDes;
                 } else {
-                    if (mUseBoundsForWidth) {
-                        RectF bbox = boring.getDrawingBoundingBox();
-                        float rightMax = Math.max(bbox.right, boring.width);
-                        float leftMin = Math.min(bbox.left, 0);
-                        width = Math.max(boring.width, (int) Math.ceil(rightMax - leftMin));
-                    } else {
-                        width = boring.width;
-                    }
+                    hintWidth = hintBoring.width;
                 }
 
-                final Drawables dr = mDrawables;
-                if (dr != null) {
-                    width = Math.max(width, dr.mDrawableWidthTop);
-                    width = Math.max(width, dr.mDrawableWidthBottom);
-                }
-
-                if (mHint != null) {
-                    int hintDes = -1;
-                    int hintWidth;
-
-                    if (mHintLayout != null && mEllipsize == null) {
-                        hintDes = desired(mHintLayout, mUseBoundsForWidth);
-                    }
-
-                    if (hintDes < 0) {
-                        hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mTextDir,
-                                isFallbackLineSpacingForBoringLayout(),
-                                getResolvedMinimumFontMetrics(),
-                                mHintBoring);
-                        if (hintBoring != null) {
-                            mHintBoring = hintBoring;
-                        }
-                    }
-
-                    if (hintBoring == null || hintBoring == UNKNOWN_BORING) {
-                        if (hintDes < 0) {
-                            hintDes = (int) Math.ceil(Layout.getDesiredWidthWithLimit(mHint, 0,
-                                    mHint.length(), mTextPaint, mTextDir, widthLimit,
-                                    mUseBoundsForWidth));
-                        }
-                        hintWidth = hintDes;
-                    } else {
-                        hintWidth = hintBoring.width;
-                    }
-
-                    if (hintWidth > width) {
-                        width = hintWidth;
-                    }
-                }
-
-                width += getCompoundPaddingLeft() + getCompoundPaddingRight();
-
-                if (mMaxWidthMode == EMS) {
-                    width = Math.min(width, mMaxWidth * getLineHeight());
-                } else {
-                    width = Math.min(width, mMaxWidth);
-                }
-
-                if (mMinWidthMode == EMS) {
-                    width = Math.max(width, mMinWidth * getLineHeight());
-                } else {
-                    width = Math.max(width, mMinWidth);
-                }
-
-                // Check against our minimum width
-                width = Math.max(width, getSuggestedMinimumWidth());
-
-                if (widthMode == MeasureSpec.AT_MOST) {
-                    width = Math.min(widthSize, width);
+                if (hintWidth > width) {
+                    width = hintWidth;
                 }
             }
 
-            int want = width - getCompoundPaddingLeft() - getCompoundPaddingRight();
-            int unpaddedWidth = want;
+            width += getCompoundPaddingLeft() + getCompoundPaddingRight();
 
-            if (mHorizontallyScrolling) want = VERY_WIDE;
-
-            int hintWant = want;
-            int hintWidth = (mHintLayout == null) ? hintWant : mHintLayout.getWidth();
-
-            if (mLayout == null) {
-                makeNewLayout(want, hintWant, boring, hintBoring,
-                        width - getCompoundPaddingLeft() - getCompoundPaddingRight(), false);
+            if (mMaxWidthMode == EMS) {
+                width = Math.min(width, mMaxWidth * getLineHeight());
             } else {
-                final boolean layoutChanged =
-                        (mLayout.getWidth() != want) || (hintWidth != hintWant)
-                                || (mLayout.getEllipsizedWidth()
-                                != width - getCompoundPaddingLeft() - getCompoundPaddingRight());
-
-                final boolean widthChanged = (mHint == null) && (mEllipsize == null)
-                        && (want > mLayout.getWidth())
-                        && (mLayout instanceof BoringLayout
-                        || (fromexisting && des >= 0 && des <= want));
-
-                final boolean maximumChanged =
-                        (mMaxMode != mOldMaxMode) || (mMaximum != mOldMaximum);
-
-                if (layoutChanged || maximumChanged) {
-                    if (!maximumChanged && widthChanged) {
-                        mLayout.increaseWidthTo(want);
-                    } else {
-                        makeNewLayout(want, hintWant, boring, hintBoring,
-                                width - getCompoundPaddingLeft() - getCompoundPaddingRight(),
-                                false);
-                    }
-                } else {
-                    // Nothing has changed
-                }
+                width = Math.min(width, mMaxWidth);
             }
 
-            if (heightMode == MeasureSpec.EXACTLY) {
-                // Parent has told us how big to be. So be it.
-                height = heightSize;
-                mDesiredHeightAtMeasure = -1;
+            if (mMinWidthMode == EMS) {
+                width = Math.max(width, mMinWidth * getLineHeight());
             } else {
-                int desired = getDesiredHeight();
-
-                height = desired;
-                mDesiredHeightAtMeasure = desired;
-
-                if (heightMode == MeasureSpec.AT_MOST) {
-                    height = Math.min(desired, heightSize);
-                }
+                width = Math.max(width, mMinWidth);
             }
 
-            int unpaddedHeight = height - getCompoundPaddingTop() - getCompoundPaddingBottom();
-            if (mMaxMode == LINES && mLayout.getLineCount() > mMaximum) {
-                unpaddedHeight = Math.min(unpaddedHeight, mLayout.getLineTop(mMaximum));
-            }
+            // Check against our minimum width
+            width = Math.max(width, getSuggestedMinimumWidth());
 
-            /*
-             * We didn't let makeNewLayout() register to bring the cursor into view,
-             * so do it here if there is any possibility that it is needed.
-             */
-            if (mMovement != null
-                    || mLayout.getWidth() > unpaddedWidth
-                    || mLayout.getHeight() > unpaddedHeight) {
-                registerForPreDraw();
-            } else {
-                scrollTo(0, 0);
+            if (widthMode == MeasureSpec.AT_MOST) {
+                width = Math.min(widthSize, width);
             }
-
-            setMeasuredDimension(width, height);
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
         }
+
+        int want = width - getCompoundPaddingLeft() - getCompoundPaddingRight();
+        int unpaddedWidth = want;
+
+        if (mHorizontallyScrolling) want = VERY_WIDE;
+
+        int hintWant = want;
+        int hintWidth = (mHintLayout == null) ? hintWant : mHintLayout.getWidth();
+
+        if (mLayout == null) {
+            makeNewLayout(want, hintWant, boring, hintBoring,
+                          width - getCompoundPaddingLeft() - getCompoundPaddingRight(), false);
+        } else {
+            final boolean layoutChanged = (mLayout.getWidth() != want) || (hintWidth != hintWant)
+                    || (mLayout.getEllipsizedWidth()
+                            != width - getCompoundPaddingLeft() - getCompoundPaddingRight());
+
+            final boolean widthChanged = (mHint == null) && (mEllipsize == null)
+                    && (want > mLayout.getWidth())
+                    && (mLayout instanceof BoringLayout
+                            || (fromexisting && des >= 0 && des <= want));
+
+            final boolean maximumChanged = (mMaxMode != mOldMaxMode) || (mMaximum != mOldMaximum);
+
+            if (layoutChanged || maximumChanged) {
+                if (!maximumChanged && widthChanged) {
+                    mLayout.increaseWidthTo(want);
+                } else {
+                    makeNewLayout(want, hintWant, boring, hintBoring,
+                            width - getCompoundPaddingLeft() - getCompoundPaddingRight(), false);
+                }
+            } else {
+                // Nothing has changed
+            }
+        }
+
+        if (heightMode == MeasureSpec.EXACTLY) {
+            // Parent has told us how big to be. So be it.
+            height = heightSize;
+            mDesiredHeightAtMeasure = -1;
+        } else {
+            int desired = getDesiredHeight();
+
+            height = desired;
+            mDesiredHeightAtMeasure = desired;
+
+            if (heightMode == MeasureSpec.AT_MOST) {
+                height = Math.min(desired, heightSize);
+            }
+        }
+
+        int unpaddedHeight = height - getCompoundPaddingTop() - getCompoundPaddingBottom();
+        if (mMaxMode == LINES && mLayout.getLineCount() > mMaximum) {
+            unpaddedHeight = Math.min(unpaddedHeight, mLayout.getLineTop(mMaximum));
+        }
+
+        /*
+         * We didn't let makeNewLayout() register to bring the cursor into view,
+         * so do it here if there is any possibility that it is needed.
+         */
+        if (mMovement != null
+                || mLayout.getWidth() > unpaddedWidth
+                || mLayout.getHeight() > unpaddedHeight) {
+            registerForPreDraw();
+        } else {
+            scrollTo(0, 0);
+        }
+
+        setMeasuredDimension(width, height);
     }
 
     /**
diff --git a/core/java/android/window/IBackAnimationHandoffHandler.aidl b/core/java/android/window/IBackAnimationHandoffHandler.aidl
new file mode 100644
index 0000000..577948d
--- /dev/null
+++ b/core/java/android/window/IBackAnimationHandoffHandler.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.window;
+
+import android.os.Bundle;
+import android.view.RemoteAnimationTarget;
+import android.window.BackMotionEvent;
+import android.window.WindowAnimationState;
+
+
+/**
+ * Interface that allows an {@link OnBackInvokedCallback} object to hand off an animation to another
+ * handler.
+ *
+ * @hide
+ */
+oneway interface IBackAnimationHandoffHandler {
+    /**
+     * Triggers a handoff of the animation of the given targets and their associated states.
+     * Important: since this is a one-way method, the caller must first make sure that the animation
+     * can indeed be taken over.
+     */
+    oneway void handOffAnimation(in RemoteAnimationTarget[] targets,
+                    in WindowAnimationState[] states);
+}
diff --git a/core/java/android/window/IOnBackInvokedCallback.aidl b/core/java/android/window/IOnBackInvokedCallback.aidl
index e07d4a9..81ad4b7 100644
--- a/core/java/android/window/IOnBackInvokedCallback.aidl
+++ b/core/java/android/window/IOnBackInvokedCallback.aidl
@@ -18,6 +18,7 @@
 package android.window;
 
 import android.window.BackMotionEvent;
+import android.window.IBackAnimationHandoffHandler;
 
 /**
  * Interface that wraps a {@link OnBackInvokedCallback} object, to be stored in window manager
@@ -61,4 +62,9 @@
      * Sets whether the back gesture is past the trigger threshold.
      */
     void setTriggerBack(in boolean triggerBack);
+
+   /**
+    * Sets a {@link IBackAnimationHandoffHandler} that can be used to hand off the back animation.
+    */
+    void setHandoffHandler(in IBackAnimationHandoffHandler handoffHandler);
 }
diff --git a/core/java/android/window/ImeOnBackInvokedDispatcher.java b/core/java/android/window/ImeOnBackInvokedDispatcher.java
index c67b9ca..d478108 100644
--- a/core/java/android/window/ImeOnBackInvokedDispatcher.java
+++ b/core/java/android/window/ImeOnBackInvokedDispatcher.java
@@ -392,6 +392,11 @@
             // no-op
         }
 
+        @Override
+        public void setHandoffHandler(IBackAnimationHandoffHandler handoffHandler) {
+            // no-op
+        }
+
         private void maybeRunOnAnimationCallback(Consumer<OnBackAnimationCallback> block) {
             if (mCallback instanceof OnBackAnimationCallback) {
                 mHandler.post(() -> block.accept((OnBackAnimationCallback) mCallback));
diff --git a/core/java/android/window/WindowContext.java b/core/java/android/window/WindowContext.java
index fdaab66..2b370b9 100644
--- a/core/java/android/window/WindowContext.java
+++ b/core/java/android/window/WindowContext.java
@@ -94,6 +94,23 @@
         mController.attachToDisplayArea(mType, getDisplayId(), mOptions);
     }
 
+    /**
+     * Updates this context to a new displayId.
+     * <p>
+     * Note that this doesn't re-parent previously attached windows (they should be removed and
+     * re-added manually after this is called). Resources associated with this context will have
+     * the correct value and configuration for the new display after this is called.
+     */
+    @Override
+    public void updateDisplay(int displayId) {
+        if (displayId == getDisplayId()) {
+            return;
+        }
+        super.updateDisplay(displayId);
+        mController.detachIfNeeded();
+        mController.attachToDisplayArea(mType, displayId, mOptions);
+    }
+
     @Override
     public Object getSystemService(String name) {
         if (WINDOW_SERVICE.equals(name)) {
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 0ea4bb4..20e3f6b 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -546,6 +546,11 @@
         }
 
         @Override
+        public void setHandoffHandler(IBackAnimationHandoffHandler handoffHandler) {
+            // no-op
+        }
+
+        @Override
         public void onBackProgressed(BackMotionEvent backEvent) {
             // This is only called in some special cases such as when activity embedding is active
             // or when the activity is letterboxed. Otherwise mProgressAnimator#onBackProgressed is
diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java
index 15adc80..6e76d8d 100644
--- a/core/java/android/window/WindowTokenClient.java
+++ b/core/java/android/window/WindowTokenClient.java
@@ -19,6 +19,8 @@
 import static android.window.ConfigurationHelper.isDifferentDisplay;
 import static android.window.ConfigurationHelper.shouldUpdateResources;
 
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
 import android.annotation.AnyThread;
 import android.annotation.MainThread;
 import android.annotation.NonNull;
@@ -104,7 +106,7 @@
      * @param newConfig the updated {@link Configuration}
      * @param newDisplayId the updated {@link android.view.Display} ID
      */
-    @VisibleForTesting
+    @VisibleForTesting(visibility = PACKAGE)
     @MainThread
     public void onConfigurationChanged(Configuration newConfig, int newDisplayId) {
         onConfigurationChanged(newConfig, newDisplayId, true /* shouldReportConfigChange */);
@@ -113,7 +115,7 @@
     /**
      * Posts an {@link #onConfigurationChanged} to the main thread.
      */
-    @VisibleForTesting
+    @VisibleForTesting(visibility = PACKAGE)
     public void postOnConfigurationChanged(@NonNull Configuration newConfig, int newDisplayId) {
         mHandler.post(PooledLambda.obtainRunnable(this::onConfigurationChanged, newConfig,
                 newDisplayId, true /* shouldReportConfigChange */).recycleOnUse());
@@ -232,7 +234,7 @@
     /**
      * Called when the attached window is removed from the display.
      */
-    @VisibleForTesting
+    @VisibleForTesting(visibility = PACKAGE)
     @MainThread
     public void onWindowTokenRemoved() {
         final Context context = mContextRef.get();
diff --git a/core/java/android/window/WindowTokenClientController.java b/core/java/android/window/WindowTokenClientController.java
index abf7bb1..fa34595 100644
--- a/core/java/android/window/WindowTokenClientController.java
+++ b/core/java/android/window/WindowTokenClientController.java
@@ -28,7 +28,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 import android.view.IWindowManager;
 import android.view.WindowManagerGlobal;
@@ -50,9 +50,9 @@
     private final IApplicationThread mAppThread = ActivityThread.currentActivityThread()
             .getApplicationThread();
 
-    /** Mapping from a client defined token to the {@link WindowTokenClient} it represents. */
+    /** Attached {@link WindowTokenClient}. */
     @GuardedBy("mLock")
-    private final ArrayMap<IBinder, WindowTokenClient> mWindowTokenClientMap = new ArrayMap<>();
+    private final ArraySet<WindowTokenClient> mWindowTokenClients = new ArraySet<>();
 
     /** Gets the singleton controller. */
     @NonNull
@@ -85,11 +85,15 @@
     /** Gets the {@link WindowContext} instance for the token. */
     @Nullable
     public Context getWindowContext(@NonNull IBinder clientToken) {
-        final WindowTokenClient windowTokenClient;
-        synchronized (mLock) {
-            windowTokenClient = mWindowTokenClientMap.get(clientToken);
+        if (!(clientToken instanceof WindowTokenClient windowTokenClient)) {
+            return null;
         }
-        return windowTokenClient != null ? windowTokenClient.getContext() : null;
+        synchronized (mLock) {
+            if (!mWindowTokenClients.contains(windowTokenClient)) {
+                return null;
+            }
+        }
+        return windowTokenClient.getContext();
     }
 
     /**
@@ -126,8 +130,14 @@
      */
     public boolean attachToDisplayContent(@NonNull WindowTokenClient client, int displayId) {
         final IWindowManager wms = getWindowManagerService();
-        // #createSystemUiContext may call this method before WindowManagerService is initialized.
         if (wms == null) {
+            // #createSystemUiContext may call this method before WindowManagerService is
+            // initialized.
+            // Regardless of whether or not it is ready, keep track of the token so that when WMS
+            // is initialized later, the SystemUiContext will start reporting from
+            // DisplayContent#registerSystemUiContext, and WindowTokenClientController can report
+            // the Configuration to the correct client.
+            recordWindowContextToken(client);
             return false;
         }
         final WindowContextInfo info;
@@ -170,12 +180,18 @@
     /** Detaches a {@link WindowTokenClient} from associated WindowContainer if there's one. */
     public void detachIfNeeded(@NonNull WindowTokenClient client) {
         synchronized (mLock) {
-            if (mWindowTokenClientMap.remove(client) == null) {
+            if (!mWindowTokenClients.remove(client)) {
                 return;
             }
         }
+        final IWindowManager wms = getWindowManagerService();
+        if (wms == null) {
+            // #createSystemUiContext may call this method before WindowManagerService is
+            // initialized. If it is GC'ed before WMS is initialized, skip calling into WMS.
+            return;
+        }
         try {
-            getWindowManagerService().detachWindowContext(client);
+            wms.detachWindowContext(client);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -183,9 +199,7 @@
 
     private void onWindowContextTokenAttached(@NonNull WindowTokenClient client,
             @NonNull WindowContextInfo info, boolean shouldReportConfigChange) {
-        synchronized (mLock) {
-            mWindowTokenClientMap.put(client, client);
-        }
+        recordWindowContextToken(client);
         if (shouldReportConfigChange) {
             // Should trigger an #onConfigurationChanged callback to the WindowContext. Post the
             // dispatch in the next loop to prevent the callback from being dispatched before
@@ -199,10 +213,16 @@
         }
     }
 
+    private void recordWindowContextToken(@NonNull WindowTokenClient client) {
+        synchronized (mLock) {
+            mWindowTokenClients.add(client);
+        }
+    }
+
     /** Called when receives {@link WindowContextInfoChangeItem}. */
     public void onWindowContextInfoChanged(@NonNull IBinder clientToken,
             @NonNull WindowContextInfo info) {
-        final WindowTokenClient windowTokenClient = getWindowTokenClient(clientToken);
+        final WindowTokenClient windowTokenClient = getWindowTokenClientIfAttached(clientToken);
         if (windowTokenClient != null) {
             windowTokenClient.onConfigurationChanged(info.getConfiguration(), info.getDisplayId());
         }
@@ -210,20 +230,23 @@
 
     /** Called when receives {@link WindowContextWindowRemovalItem}. */
     public void onWindowContextWindowRemoved(@NonNull IBinder clientToken) {
-        final WindowTokenClient windowTokenClient = getWindowTokenClient(clientToken);
+        final WindowTokenClient windowTokenClient = getWindowTokenClientIfAttached(clientToken);
         if (windowTokenClient != null) {
             windowTokenClient.onWindowTokenRemoved();
         }
     }
 
     @Nullable
-    private WindowTokenClient getWindowTokenClient(@NonNull IBinder clientToken) {
-        final WindowTokenClient windowTokenClient;
-        synchronized (mLock) {
-            windowTokenClient = mWindowTokenClientMap.get(clientToken);
+    private WindowTokenClient getWindowTokenClientIfAttached(@NonNull IBinder clientToken) {
+        if (!(clientToken instanceof WindowTokenClient windowTokenClient)) {
+            Log.e(TAG, "getWindowTokenClient failed for non-window token " + clientToken);
+            return null;
         }
-        if (windowTokenClient == null) {
-            Log.w(TAG, "Can't find attached WindowTokenClient for " + clientToken);
+        synchronized (mLock) {
+            if (!mWindowTokenClients.contains(windowTokenClient)) {
+                Log.w(TAG, "Can't find attached WindowTokenClient for " + clientToken);
+                return null;
+            }
         }
         return windowTokenClient;
     }
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index eebdeadc..65e5679 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -58,10 +58,13 @@
 }
 
 flag {
-    name: "enable_desktop_windowing_scvh_cache"
+    name: "enable_desktop_windowing_scvh_cache_bug_fix"
     namespace: "lse_desktop_experience"
     description: "Enables a SurfaceControlViewHost cache for window decorations"
-    bug: "345146928"
+    bug: "360452034"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
 }
 
 flag {
@@ -256,6 +259,16 @@
 }
 
 flag {
+    name: "enable_desktop_windowing_enter_transition_bugfix"
+    namespace: "lse_desktop_experience"
+    description: "Enables enter desktop windowing transition & motion polish changes"
+    bug: "380224875"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "enable_desktop_windowing_exit_transitions"
     namespace: "lse_desktop_experience"
     description: "Enables exit desktop windowing transition & motion polish changes"
@@ -263,6 +276,16 @@
 }
 
 flag {
+    name: "enable_desktop_windowing_exit_transitions_bugfix"
+    namespace: "lse_desktop_experience"
+    description: "Enables exit desktop windowing transition & motion polish changes"
+    bug: "380224768"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "enable_compat_ui_visibility_status"
     namespace: "lse_desktop_experience"
     description: "Enables the tracking of the status for compat ui elements."
@@ -277,6 +300,13 @@
 }
 
 flag {
+    name: "enable_desktop_windowing_app_to_web_education_integration"
+    namespace: "lse_desktop_experience"
+    description: "Enables desktop windowing App-to-Web education and integrates new APIs"
+    bug: "380272815"
+}
+
+flag {
     name: "enable_minimize_button"
     namespace: "lse_desktop_experience"
     description: "Adds a minimize button the the caption bar"
@@ -346,6 +376,16 @@
 }
 
 flag {
+    name: "enable_desktop_app_launch_alttab_transitions_bugfix"
+    namespace: "lse_desktop_experience"
+    description: "Enables custom transitions for alt-tab app launches in Desktop Mode."
+    bug: "380225486"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "enable_desktop_app_launch_transitions"
     namespace: "lse_desktop_experience"
     description: "Enables custom transitions for app launches in Desktop Mode."
@@ -353,6 +393,16 @@
 }
 
 flag {
+    name: "enable_desktop_app_launch_transitions_bugfix"
+    namespace: "lse_desktop_experience"
+    description: "Enables custom transitions for app launches in Desktop Mode."
+    bug: "380224832"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "enable_desktop_system_dialogs_transitions"
     namespace: "lse_desktop_experience"
     description: "Enables custom transitions for system dialogs in Desktop Mode."
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 86bbeb8..ebbe483 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -441,3 +441,11 @@
     description: "Enable Predictive Back Animation for 3-button-nav"
     bug: "373544911"
 }
+
+flag {
+    name: "predictive_back_default_enable_sdk_36"
+    namespace: "systemui"
+    description: "Enable Predictive Back by default with targetSdk>=36"
+    is_fixed_read_only: true
+    bug: "376407910"
+}
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index e8831ec..e2be1f5 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -360,43 +360,44 @@
 
         // Avoid non-a11y users accidentally turning shortcut on without reading this carefully.
         // Put "don't turn on" as the primary action.
-        final AlertDialog alertDialog = mFrameworkObjectProvider.getAlertDialogBuilder(
-                        // Use SystemUI context so we pick up any theme set in a vendor overlay
-                        mFrameworkObjectProvider.getSystemUiContext())
-                .setTitle(getShortcutWarningTitle(targets))
-                .setMessage(getShortcutWarningMessage(targets))
-                .setCancelable(false)
-                .setNegativeButton(R.string.accessibility_shortcut_on,
-                        (DialogInterface d, int which) -> enableDefaultHardwareShortcut(userId))
-                .setPositiveButton(R.string.accessibility_shortcut_off,
-                        (DialogInterface d, int which) -> {
-                            Set<String> targetServices =
-                                    ShortcutUtils.getShortcutTargetsFromSettings(
-                                            mContext,
-                                            HARDWARE,
+        final AlertDialog alertDialog =
+                mFrameworkObjectProvider
+                        .getAlertDialogBuilder(
+                                // Use SystemUI context so we pick up any theme set in a vendor
+                                // overlay
+                                mFrameworkObjectProvider.getSystemUiContext())
+                        .setTitle(getShortcutWarningTitle(targets))
+                        .setMessage(getShortcutWarningMessage(targets))
+                        .setCancelable(false)
+                        .setNegativeButton(
+                                R.string.accessibility_shortcut_on,
+                                (DialogInterface d, int which) ->
+                                        enableDefaultHardwareShortcut(userId))
+                        .setPositiveButton(
+                                R.string.accessibility_shortcut_off,
+                                (DialogInterface d, int which) -> {
+                                    Set<String> targetServices =
+                                            ShortcutUtils.getShortcutTargetsFromSettings(
+                                                    mContext, HARDWARE, userId);
+                                    am.enableShortcutsForTargets(
+                                            false, HARDWARE, targetServices, userId);
+                                    // If canceled, treat as if the dialog has never been shown
+                                    Settings.Secure.putIntForUser(
+                                            mContext.getContentResolver(),
+                                            Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+                                            DialogStatus.NOT_SHOWN,
                                             userId);
-                            if (Flags.migrateEnableShortcuts()) {
-                                am.enableShortcutsForTargets(
-                                        false, HARDWARE, targetServices, userId);
-                            } else {
-                                Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                                        Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "",
-                                        userId);
-                                ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState(
-                                        mContext, targetServices, userId);
-                            }
-                            // If canceled, treat as if the dialog has never been shown
-                            Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                                    Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
-                                    DialogStatus.NOT_SHOWN, userId);
-                        })
-                .setOnCancelListener((DialogInterface d) -> {
-                    // If canceled, treat as if the dialog has never been shown
-                    Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                            Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
-                            DialogStatus.NOT_SHOWN, userId);
-                })
-                .create();
+                                })
+                        .setOnCancelListener(
+                                (DialogInterface d) -> {
+                                    // If canceled, treat as if the dialog has never been shown
+                                    Settings.Secure.putIntForUser(
+                                            mContext.getContentResolver(),
+                                            Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+                                            DialogStatus.NOT_SHOWN,
+                                            userId);
+                                })
+                        .create();
         return alertDialog;
     }
 
@@ -531,14 +532,8 @@
             // Default service is invalid, so nothing we can do here.
             return;
         }
-        if (Flags.migrateEnableShortcuts()) {
-            accessibilityManager.enableShortcutsForTargets(true, HARDWARE,
-                    Set.of(defaultServiceComponent.flattenToString()), userId);
-        } else {
-            Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                    Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
-                    defaultServiceComponent.flattenToString(), userId);
-        }
+        accessibilityManager.enableShortcutsForTargets(true, HARDWARE,
+                Set.of(defaultServiceComponent.flattenToString()), userId);
     }
 
     private boolean performTtsPrompt(AlertDialog alertDialog) {
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java
index a753110..f0582d0 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java
@@ -19,8 +19,6 @@
 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
-import static com.android.internal.accessibility.util.ShortcutUtils.optInValueToSettings;
-import static com.android.internal.accessibility.util.ShortcutUtils.optOutValueFromSettings;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -31,7 +29,6 @@
 import android.os.UserHandle;
 import android.view.View;
 import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.Flags;
 
 import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
@@ -118,18 +115,9 @@
     @Override
     public void onCheckedChanged(boolean isChecked) {
         setShortcutEnabled(isChecked);
-        if (Flags.migrateEnableShortcuts()) {
-            final AccessibilityManager am =
-                    getContext().getSystemService(AccessibilityManager.class);
-            am.enableShortcutsForTargets(
-                    isChecked, getShortcutType(), Set.of(mId), UserHandle.myUserId());
-        } else {
-            if (isChecked) {
-                optInValueToSettings(getContext(), getShortcutType(), getId());
-            } else {
-                optOutValueFromSettings(getContext(), getShortcutType(), getId());
-            }
-        }
+        final AccessibilityManager am = getContext().getSystemService(AccessibilityManager.class);
+        am.enableShortcutsForTargets(
+                isChecked, getShortcutType(), Set.of(mId), UserHandle.myUserId());
     }
 
     public void setStateDescription(CharSequence stateDescription) {
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 0c56c67..6ad7fef 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -26,6 +26,7 @@
 import static android.system.OsConstants.S_IXOTH;
 
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.parsing.ApkLiteParseUtils;
 import android.content.pm.parsing.PackageLite;
@@ -177,6 +178,13 @@
     private native static int nativeCopyNativeBinaries(long handle, String sharedLibraryPath,
             String abiToCopy, boolean extractNativeLibs, boolean debuggable);
 
+    private static native int nativeCheckAlignment(
+            long handle,
+            String sharedLibraryPath,
+            String abi,
+            boolean extractNativeLibs,
+            boolean debuggable);
+
     private static long sumNativeBinaries(Handle handle, String abi) {
         long sum = 0;
         for (long apkHandle : handle.apkHandles) {
@@ -432,6 +440,51 @@
         }
     }
 
+    /**
+     * Checks alignment of APK and native libraries for 16KB device
+     *
+     * @param handle APK file to scan for native libraries
+     * @param libraryRoot directory for libraries
+     * @param abiOverride abiOverride for package
+     * @return {@link Modes from ApplicationInfo.PageSizeAppCompat} if successful or error code
+     *     which suggests undefined mode
+     */
+    @ApplicationInfo.PageSizeAppCompatFlags
+    public static int checkAlignmentForCompatMode(
+            Handle handle,
+            String libraryRoot,
+            boolean nativeLibraryRootRequiresIsa,
+            String abiOverride) {
+        // Keep the code below in sync with copyNativeBinariesForSupportedAbi
+        int abi = findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS);
+        if (abi < 0) {
+            return ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
+        }
+
+        final String supportedAbi = Build.SUPPORTED_64_BIT_ABIS[abi];
+        final String instructionSet = VMRuntime.getInstructionSet(supportedAbi);
+        String subDir = libraryRoot;
+        if (nativeLibraryRootRequiresIsa) {
+            subDir += "/" + instructionSet;
+        }
+
+        int mode = ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED;
+        for (long apkHandle : handle.apkHandles) {
+            int res =
+                    nativeCheckAlignment(
+                            apkHandle,
+                            subDir,
+                            Build.SUPPORTED_64_BIT_ABIS[abi],
+                            handle.extractNativeLibs,
+                            handle.debuggable);
+            if (res == ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_ERROR) {
+                return res;
+            }
+            mode |= res;
+        }
+        return mode;
+    }
+
     public static long sumNativeBinariesWithOverride(Handle handle, String abiOverride)
             throws IOException {
         long sum = 0;
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
index ac4c066..5fbb92d 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
@@ -16,6 +16,7 @@
 
 package com.android.internal.inputmethod;
 
+import android.graphics.Region;
 import android.net.Uri;
 import android.view.inputmethod.ImeTracker;
 import android.view.inputmethod.InputMethodSubtype;
@@ -51,4 +52,5 @@
     void resetStylusHandwriting(int requestId);
     void switchKeyboardLayoutAsync(int direction);
     void setHandwritingSurfaceNotTouchable(boolean notTouchable);
+    void setHandwritingTouchableRegion(in Region region);
 }
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index b009c99..36333a9 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -20,6 +20,7 @@
 import android.annotation.DrawableRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.graphics.Region;
 import android.inputmethodservice.InputMethodService.BackDispositionMode;
 import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
 import android.net.Uri;
@@ -159,6 +160,25 @@
         }
     }
 
+
+    /**
+     * Calls {@link IInputMethodPrivilegedOperations#setHandwritingTouchableRegion(Region)}.
+     *
+     * @param region {@link Region} to set handwritable.
+     */
+    @AnyThread
+    public void setHandwritingTouchableRegion(Region region) {
+        final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
+        if (ops == null) {
+            return;
+        }
+        try {
+            ops.setHandwritingTouchableRegion(region);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /**
      * Calls {@link IInputMethodPrivilegedOperations#createInputContentUriToken(Uri, String,
      * AndroidFuture)}.
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index eb6a810..429a6a2 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -89,6 +89,8 @@
         SoftInputShowHideReason.SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT,
         SoftInputShowHideReason.SHOW_SOFT_INPUT_IMM_DEPRECATION,
         SoftInputShowHideReason.CONTROL_WINDOW_INSETS_ANIMATION,
+        SoftInputShowHideReason.SHOW_INPUT_TARGET_CHANGED,
+        SoftInputShowHideReason.HIDE_INPUT_TARGET_CHANGED,
 })
 public @interface SoftInputShowHideReason {
     /** Default, undefined reason. */
@@ -337,6 +339,18 @@
     int HIDE_WINDOW_LEGACY_DIRECT = ImeProtoEnums.REASON_HIDE_WINDOW_LEGACY_DIRECT;
 
     /**
+     * Show soft input because the input target changed
+     * {@link com.android.server.wm.ImeInsetsSourceProvider#onInputTargetChanged}.
+     */
+    int SHOW_INPUT_TARGET_CHANGED = ImeProtoEnums.REASON_SHOW_INPUT_TARGET_CHANGED;
+
+    /**
+     * Hide soft input because the input target changed by
+     * {@link com.android.server.wm.ImeInsetsSourceProvider#onInputTargetChanged}.
+     */
+    int HIDE_INPUT_TARGET_CHANGED = ImeProtoEnums.REASON_HIDE_INPUT_TARGET_CHANGED;
+
+    /**
      * Show / Hide soft input by
      * {@link android.inputmethodservice.InputMethodService#resetStateForNewConfiguration}.
      */
diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java
index 1204ef3..fc41537 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -235,8 +235,19 @@
      */
     public static final int CUJ_DESKTOP_MODE_SNAP_RESIZE = 118;
 
+    /**
+     * Track unmaximize window interaction in desktop mode.
+     *
+     * <p> Tracking starts when the maximize button or option is clicked {@link
+     * com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel#onClick}
+     * and finishes when the animation finishes {@link
+     * com.android.wm.shell.windowdecor.ToggleResizeDesktopTaskTransitionHandler#startAnimation}
+     * </p>
+     */
+    public static final int CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW = 119;
+
     // When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE.
-    @VisibleForTesting static final int LAST_CUJ = CUJ_DESKTOP_MODE_SNAP_RESIZE;
+    @VisibleForTesting static final int LAST_CUJ = CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW;
 
     /** @hide */
     @IntDef({
@@ -346,7 +357,8 @@
             CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_APP_LAUNCH,
             CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE,
             CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE,
-            CUJ_DESKTOP_MODE_SNAP_RESIZE
+            CUJ_DESKTOP_MODE_SNAP_RESIZE,
+            CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface CujType {}
@@ -467,6 +479,7 @@
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE;
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE;
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_SNAP_RESIZE] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_SNAP_RESIZE;
+        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_UNMAXIMIZE_WINDOW;
     }
 
     private Cuj() {
@@ -699,6 +712,8 @@
                 return "DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE";
             case CUJ_DESKTOP_MODE_SNAP_RESIZE:
                 return "DESKTOP_MODE_SNAP_RESIZE";
+            case CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW:
+                return "DESKTOP_MODE_UNMAXIMIZE_WINDOW";
         }
         return "UNKNOWN";
     }
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index fafa085..cd17ed8 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -201,6 +201,9 @@
      */
     public static final int DEBUG_ENABLE_PTRACE = 1 << 25;
 
+    /** Load 4KB ELF files on 16KB device using appcompat mode */
+    public static final int ENABLE_PAGE_SIZE_APP_COMPAT = 1 << 26;
+
     /** No external storage should be mounted. */
     public static final int MOUNT_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE;
     /** Default external storage should be mounted. */
diff --git a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
index 48d0d6c..5ec5762 100644
--- a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
@@ -392,6 +392,10 @@
     private int memtagMode;
     @ApplicationInfo.NativeHeapZeroInitialized
     private int nativeHeapZeroInitialized;
+
+    @ApplicationInfo.PageSizeAppCompatFlags private int mPageSizeAppCompatFlags =
+            ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED;
+
     @Nullable
     @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class)
     private Boolean requestRawExternalStorageAccess;
@@ -1118,6 +1122,12 @@
         return nativeHeapZeroInitialized;
     }
 
+    @ApplicationInfo.PageSizeAppCompatFlags
+    @Override
+    public int getPageSizeAppCompatFlags() {
+        return mPageSizeAppCompatFlags;
+    }
+
     @Override
     public int getNetworkSecurityConfigResourceId() {
         return networkSecurityConfigRes;
@@ -2221,6 +2231,12 @@
     }
 
     @Override
+    public PackageImpl setPageSizeAppCompatFlags(@ApplicationInfo.PageSizeAppCompatFlags int flag) {
+        mPageSizeAppCompatFlags = flag;
+        return this;
+    }
+
+    @Override
     public PackageImpl setNetworkSecurityConfigResourceId(int value) {
         networkSecurityConfigRes = value;
         return this;
@@ -2703,6 +2719,7 @@
             appInfo.setKnownActivityEmbeddingCerts(mKnownActivityEmbeddingCerts);
         }
         appInfo.allowCrossUidActivitySwitchFromBelow = mAllowCrossUidActivitySwitchFromBelow;
+        appInfo.setPageSizeAppCompatFlags(mPageSizeAppCompatFlags);
 
         return appInfo;
     }
@@ -3305,6 +3322,7 @@
         dest.writeInt(this.mIntentMatchingFlags);
         dest.writeIntArray(this.mAlternateLauncherIconResIds);
         dest.writeIntArray(this.mAlternateLauncherLabelResIds);
+        dest.writeInt(this.mPageSizeAppCompatFlags);
     }
 
     private void writeFeatureFlagState(@NonNull Parcel dest) {
@@ -3499,6 +3517,7 @@
         this.mIntentMatchingFlags = in.readInt();
         this.mAlternateLauncherIconResIds = in.createIntArray();
         this.mAlternateLauncherLabelResIds = in.createIntArray();
+        this.mPageSizeAppCompatFlags = in.readInt();
 
         assignDerivedFields();
         assignDerivedFields2();
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
index 67b985a..5062d58 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
@@ -31,7 +31,6 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 
-import com.android.internal.R;
 import com.android.internal.pm.parsing.pkg.ParsedPackage;
 import com.android.internal.pm.pkg.component.ParsedActivity;
 import com.android.internal.pm.pkg.component.ParsedApexSystemService;
@@ -280,6 +279,9 @@
     ParsingPackage setNativeHeapZeroInitialized(
             @ApplicationInfo.NativeHeapZeroInitialized int nativeHeapZeroInitialized);
 
+    /** Manifest option pageSizeCompat will populate this field */
+    ParsingPackage setPageSizeAppCompatFlags(@ApplicationInfo.PageSizeAppCompatFlags int value);
+
     ParsingPackage setRequestRawExternalStorageAccess(
             @Nullable Boolean requestRawExternalStorageAccess);
 
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 8a6e6be..c160b42 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -29,6 +29,7 @@
 import static android.os.Build.VERSION_CODES.DONUT;
 import static android.os.Build.VERSION_CODES.O;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static android.sdk.Flags.majorMinorVersioningScheme;
 
 import static com.android.internal.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
 
@@ -541,6 +542,7 @@
 
         pkg.setGwpAsanMode(-1);
         pkg.setMemtagMode(-1);
+        pkg.setPageSizeAppCompatFlags(ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED);
 
         afterParseBaseApplication(pkg);
 
@@ -1688,6 +1690,21 @@
                     targetCode = minCode;
                 }
 
+                if (majorMinorVersioningScheme()) {
+                    val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_minSdkVersionFull);
+                    if (val != null) {
+                        if (val.type == TypedValue.TYPE_STRING && val.string != null) {
+                            String minSdkVersionFullString = val.string.toString();
+                            ParseResult<Void> minSdkVersionFullResult =
+                                    FrameworkParsingPackageUtils.verifyMinSdkVersionFull(
+                                        minSdkVersionFullString, Build.VERSION.SDK_INT_FULL, input);
+                            if (minSdkVersionFullResult.isError()) {
+                                return input.error(minSdkVersionFullResult);
+                            }
+                        }
+                    }
+                }
+
                 if (isApkInApex) {
                     val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_maxSdkVersion);
                     if (val != null) {
@@ -2182,6 +2199,13 @@
 
             pkg.setGwpAsanMode(sa.getInt(R.styleable.AndroidManifestApplication_gwpAsanMode, -1));
             pkg.setMemtagMode(sa.getInt(R.styleable.AndroidManifestApplication_memtagMode, -1));
+
+            if (Flags.appCompatOption16kb()) {
+                pkg.setPageSizeAppCompatFlags(
+                        sa.getInt(R.styleable.AndroidManifestApplication_pageSizeCompat,
+                                ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED));
+            }
+
             if (sa.hasValue(R.styleable.AndroidManifestApplication_nativeHeapZeroInitialized)) {
                 final boolean v = sa.getBoolean(
                         R.styleable.AndroidManifestApplication_nativeHeapZeroInitialized, false);
@@ -2377,6 +2401,7 @@
      * Flags are separated by type and by default value. They are sorted alphabetically within each
      * section.
      */
+    @SuppressWarnings("AndroidFrameworkCompatChange")
     private void parseBaseAppBasicFlags(ParsingPackage pkg, TypedArray sa) {
         int targetSdk = pkg.getTargetSdkVersion();
         //@formatter:off
@@ -2414,12 +2439,20 @@
                 .setResetEnabledSettingsOnAppDataCleared(bool(false,
                         R.styleable.AndroidManifestApplication_resetEnabledSettingsOnAppDataCleared,
                         sa))
-                .setOnBackInvokedCallbackEnabled(bool(false, R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback, sa))
                 // targetSdkVersion gated
                 .setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa))
                 .setHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa))
                 .setRequestLegacyExternalStorage(bool(targetSdk < Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_requestLegacyExternalStorage, sa))
                 .setCleartextTrafficAllowed(bool(targetSdk < Build.VERSION_CODES.P, R.styleable.AndroidManifestApplication_usesCleartextTraffic, sa))
+                // CompatChange.isChangeEnabled() can't be used here because this is called during
+                // PackageManagerService initialization. PlatformCompat can't be used because this
+                // code is not guaranteed to be called from the system_server process. Therefore
+                // accessing Build.VERSION_CODES directly and suppressing
+                // AndroidFrameworkCompatChange warning
+                .setOnBackInvokedCallbackEnabled(bool(
+                        com.android.window.flags.Flags.predictiveBackDefaultEnableSdk36()
+                            && targetSdk > Build.VERSION_CODES.VANILLA_ICE_CREAM,
+                        R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback, sa))
                 // Ints Default 0
                 .setUiOptions(anInt(R.styleable.AndroidManifestApplication_uiOptions, sa))
                 // Ints
diff --git a/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java b/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java
index 8771cde..be3bbb2 100644
--- a/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java
@@ -70,7 +70,7 @@
     private final TraceBuffer mBuffer;
     private final LegacyProtoLogViewerConfigReader mViewerConfig;
     private final Map<String, IProtoLogGroup> mLogGroups = new TreeMap<>();
-    private final Runnable mCacheUpdater;
+    private final ProtoLogCacheUpdater mCacheUpdater;
     private final int mPerChunkSize;
 
     private boolean mProtoLogEnabled;
@@ -78,14 +78,14 @@
     private final Object mProtoLogEnabledLock = new Object();
 
     public LegacyProtoLogImpl(String outputFile, String viewerConfigFilename,
-            Runnable cacheUpdater) {
+            ProtoLogCacheUpdater cacheUpdater) {
         this(new File(outputFile), viewerConfigFilename, BUFFER_CAPACITY,
                 new LegacyProtoLogViewerConfigReader(), PER_CHUNK_SIZE, cacheUpdater);
     }
 
     public LegacyProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity,
             LegacyProtoLogViewerConfigReader viewerConfig, int perChunkSize,
-            Runnable cacheUpdater) {
+            ProtoLogCacheUpdater cacheUpdater) {
         mLogFile = file;
         mBuffer = new TraceBuffer(bufferCapacity);
         mLegacyViewerConfigFilename = viewerConfigFilename;
@@ -298,7 +298,7 @@
             }
         }
 
-        mCacheUpdater.run();
+        mCacheUpdater.update(this);
         return 0;
     }
 
diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
index eb682df..05a33fe 100644
--- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
@@ -51,7 +51,6 @@
 import android.os.ShellCommand;
 import android.os.SystemClock;
 import android.text.TextUtils;
-import android.tracing.perfetto.DataSourceParams;
 import android.tracing.perfetto.InitArguments;
 import android.tracing.perfetto.Producer;
 import android.tracing.perfetto.TracingContext;
@@ -86,7 +85,6 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
-import java.util.stream.Stream;
 
 /**
  * A service for the ProtoLog logging system.
@@ -98,10 +96,12 @@
 
     @NonNull
     protected final ProtoLogDataSource mDataSource;
+    @Nullable
+    protected final IProtoLogConfigurationService mConfigurationService;
     @NonNull
     protected final TreeMap<String, IProtoLogGroup> mLogGroups = new TreeMap<>();
     @NonNull
-    private final Runnable mCacheUpdater;
+    private final ProtoLogCacheUpdater mCacheUpdater;
 
     @NonNull
     private final int[] mDefaultLogLevelCounts = new int[LogLevel.values().length];
@@ -117,10 +117,10 @@
     private boolean mLogcatReady = false;
 
     protected PerfettoProtoLogImpl(
-            @NonNull Runnable cacheUpdater,
+            @NonNull ProtoLogDataSource dataSource,
+            @NonNull ProtoLogCacheUpdater cacheUpdater,
             @NonNull IProtoLogGroup[] groups) throws ServiceManager.ServiceNotFoundException {
-        this(cacheUpdater, groups,
-                ProtoLogDataSource::new,
+        this(dataSource, cacheUpdater, groups,
                 android.tracing.Flags.clientSideProtoLogging() ?
                     IProtoLogConfigurationService.Stub.asInterface(
                         ServiceManager.getServiceOrThrow(PROTOLOG_CONFIGURATION_SERVICE)
@@ -129,47 +129,60 @@
     }
 
     protected PerfettoProtoLogImpl(
-            @NonNull Runnable cacheUpdater,
+            @NonNull ProtoLogDataSource dataSource,
+            @NonNull ProtoLogCacheUpdater cacheUpdater,
             @NonNull IProtoLogGroup[] groups,
-            @NonNull ProtoLogDataSourceBuilder dataSourceBuilder,
             @Nullable IProtoLogConfigurationService configurationService) {
-        mDataSource = dataSourceBuilder.build(
-                this::onTracingInstanceStart,
-                this::onTracingFlush,
-                this::onTracingInstanceStop);
-        Producer.init(InitArguments.DEFAULTS);
-        DataSourceParams params =
-                new DataSourceParams.Builder()
-                        .setBufferExhaustedPolicy(
-                                DataSourceParams
-                                        .PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP)
-                        .build();
-        // NOTE: Registering that datasource is an async operation, so there may be no data traced
-        // for some messages logged right after the construction of this class.
-        mDataSource.register(params);
-
-        this.mCacheUpdater = cacheUpdater;
+        mDataSource = dataSource;
+        mCacheUpdater = cacheUpdater;
+        mConfigurationService = configurationService;
 
         registerGroupsLocally(groups);
+    }
+
+    /**
+     * To be called to enable the ProtoLogImpl to start tracing to ProtoLog and register with all
+     * the expected ProtoLog components.
+     */
+    public void enable() {
+        Producer.init(InitArguments.DEFAULTS);
 
         if (android.tracing.Flags.clientSideProtoLogging()) {
-            Objects.requireNonNull(configurationService,
-                    "A null ProtoLog Configuration Service was provided!");
-
-            try {
-                var args = createConfigurationServiceRegisterClientArgs();
-
-                final var groupArgs = Stream.of(groups)
-                        .map(group -> new RegisterClientArgs
-                                .GroupConfig(group.name(), group.isLogToLogcat()))
-                        .toArray(RegisterClientArgs.GroupConfig[]::new);
-                args.setGroups(groupArgs);
-
-                configurationService.registerClient(this, args);
-            } catch (RemoteException e) {
-                throw new RuntimeException("Failed to register ProtoLog client");
-            }
+            connectToConfigurationService();
         }
+
+        mDataSource.registerOnStartCallback(this::onTracingInstanceStart);
+        mDataSource.registerOnFlushCallback(this::onTracingFlush);
+        mDataSource.registerOnStopCallback(this::onTracingInstanceStop);
+    }
+
+    private void connectToConfigurationService() {
+        Objects.requireNonNull(mConfigurationService,
+                "A null ProtoLog Configuration Service was provided!");
+
+        try {
+            var args = createConfigurationServiceRegisterClientArgs();
+
+            final var groupArgs = mLogGroups.values().stream()
+                    .map(group -> new RegisterClientArgs
+                            .GroupConfig(group.name(), group.isLogToLogcat()))
+                    .toArray(RegisterClientArgs.GroupConfig[]::new);
+            args.setGroups(groupArgs);
+
+            mConfigurationService.registerClient(this, args);
+        } catch (RemoteException e) {
+            throw new RuntimeException("Failed to register ProtoLog client");
+        }
+    }
+
+    /**
+     * Should be called when we no longer want to use the ProtoLog logger to unlink ourselves from
+     * the datasource and the configuration service to ensure we no longer receive the callback.
+     */
+    public void disable() {
+        mDataSource.unregisterOnStartCallback(this::onTracingInstanceStart);
+        mDataSource.unregisterOnFlushCallback(this::onTracingFlush);
+        mDataSource.unregisterOnStopCallback(this::onTracingInstanceStop);
     }
 
     @NonNull
@@ -703,7 +716,7 @@
             }
         }
 
-        mCacheUpdater.run();
+        mCacheUpdater.update(this);
         return 0;
     }
 
@@ -746,7 +759,7 @@
             }
         }
 
-        mCacheUpdater.run();
+        mCacheUpdater.update(this);
 
         this.mTracingInstances.incrementAndGet();
 
@@ -786,7 +799,7 @@
             }
         }
 
-        mCacheUpdater.run();
+        mCacheUpdater.update(this);
         Log.d(LOG_TAG, "Finished onTracingInstanceStop");
     }
 
diff --git a/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java
index 967a5ed..e0a77d2 100644
--- a/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java
@@ -42,10 +42,11 @@
     private final String mViewerConfigFilePath;
 
     public ProcessedPerfettoProtoLogImpl(
+            @NonNull ProtoLogDataSource datasource,
             @NonNull String viewerConfigFilePath,
-            @NonNull Runnable cacheUpdater,
+            @NonNull ProtoLogCacheUpdater cacheUpdater,
             @NonNull IProtoLogGroup[] groups) throws ServiceManager.ServiceNotFoundException {
-        this(viewerConfigFilePath, new ViewerConfigInputStreamProvider() {
+        this(datasource, viewerConfigFilePath, new ViewerConfigInputStreamProvider() {
                     @NonNull
                     @Override
                     public AutoClosableProtoInputStream getInputStream() {
@@ -64,11 +65,12 @@
 
     @VisibleForTesting
     public ProcessedPerfettoProtoLogImpl(
+            @NonNull ProtoLogDataSource datasource,
             @NonNull String viewerConfigFilePath,
             @NonNull ViewerConfigInputStreamProvider viewerConfigInputStreamProvider,
-            @NonNull Runnable cacheUpdater,
+            @NonNull ProtoLogCacheUpdater cacheUpdater,
             @NonNull IProtoLogGroup[] groups) throws ServiceManager.ServiceNotFoundException {
-        super(cacheUpdater, groups);
+        super(datasource, cacheUpdater, groups);
 
         this.mViewerConfigFilePath = viewerConfigFilePath;
 
@@ -80,15 +82,15 @@
 
     @VisibleForTesting
     public ProcessedPerfettoProtoLogImpl(
+            @NonNull ProtoLogDataSource datasource,
             @NonNull String viewerConfigFilePath,
             @NonNull ViewerConfigInputStreamProvider viewerConfigInputStreamProvider,
             @NonNull ProtoLogViewerConfigReader viewerConfigReader,
-            @NonNull Runnable cacheUpdater,
+            @NonNull ProtoLogCacheUpdater cacheUpdater,
             @NonNull IProtoLogGroup[] groups,
-            @NonNull ProtoLogDataSourceBuilder dataSourceBuilder,
             @Nullable IProtoLogConfigurationService configurationService)
             throws ServiceManager.ServiceNotFoundException {
-        super(cacheUpdater, groups, dataSourceBuilder, configurationService);
+        super(datasource, cacheUpdater, groups, configurationService);
 
         this.mViewerConfigFilePath = viewerConfigFilePath;
 
diff --git a/core/java/com/android/internal/protolog/ProtoLog.java b/core/java/com/android/internal/protolog/ProtoLog.java
index d117e93..c81af95 100644
--- a/core/java/com/android/internal/protolog/ProtoLog.java
+++ b/core/java/com/android/internal/protolog/ProtoLog.java
@@ -17,6 +17,9 @@
 package com.android.internal.protolog;
 
 import android.os.ServiceManager;
+import android.tracing.perfetto.DataSourceParams;
+import android.tracing.perfetto.InitArguments;
+import android.tracing.perfetto.Producer;
 
 import com.android.internal.protolog.common.IProtoLog;
 import com.android.internal.protolog.common.IProtoLogGroup;
@@ -54,6 +57,8 @@
 
     private static IProtoLog sProtoLogInstance;
 
+    private static ProtoLogDataSource sDataSource;
+
     private static final Object sInitLock = new Object();
 
     /**
@@ -69,26 +74,45 @@
         // files to extract out the log strings. Otherwise, the trace calls are replaced with calls
         // directly to the generated tracing implementations.
         if (android.tracing.Flags.perfettoProtologTracing()) {
-            synchronized (sInitLock) {
-                final var allGroups = new HashSet<>(Arrays.stream(groups).toList());
-                if (sProtoLogInstance != null) {
-                    // The ProtoLog instance has already been initialized in this process
-                    final var alreadyRegisteredGroups = sProtoLogInstance.getRegisteredGroups();
-                    allGroups.addAll(alreadyRegisteredGroups);
-                }
-
-                try {
-                    sProtoLogInstance = new UnprocessedPerfettoProtoLogImpl(
-                            allGroups.toArray(new IProtoLogGroup[0]));
-                } catch (ServiceManager.ServiceNotFoundException e) {
-                    throw new RuntimeException(e);
-                }
-            }
+            initializePerfettoProtoLog(groups);
         } else {
             sProtoLogInstance = new LogcatOnlyProtoLogImpl();
         }
     }
 
+    private static void initializePerfettoProtoLog(IProtoLogGroup... groups) {
+        var datasource = getSharedSingleInstanceDataSource();
+
+        synchronized (sInitLock) {
+            final var allGroups = new HashSet<>(Arrays.stream(groups).toList());
+            final var previousProtoLogImpl = sProtoLogInstance;
+            if (previousProtoLogImpl != null) {
+                // The ProtoLog instance has already been initialized in this process
+                final var alreadyRegisteredGroups = previousProtoLogImpl.getRegisteredGroups();
+                allGroups.addAll(alreadyRegisteredGroups);
+            }
+
+            sProtoLogInstance = createAndEnableNewPerfettoProtoLogImpl(
+                    datasource, allGroups.toArray(new IProtoLogGroup[0]));
+            if (previousProtoLogImpl instanceof PerfettoProtoLogImpl) {
+                ((PerfettoProtoLogImpl) previousProtoLogImpl).disable();
+            }
+        }
+    }
+
+    private static PerfettoProtoLogImpl createAndEnableNewPerfettoProtoLogImpl(
+            ProtoLogDataSource datasource, IProtoLogGroup[] groups) {
+        try {
+            var unprocessedPerfettoProtoLogImpl =
+                    new UnprocessedPerfettoProtoLogImpl(datasource, groups);
+            unprocessedPerfettoProtoLogImpl.enable();
+
+            return unprocessedPerfettoProtoLogImpl;
+        } catch (ServiceManager.ServiceNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     /**
      * DEBUG level log.
      *
@@ -190,6 +214,32 @@
         return sProtoLogInstance;
     }
 
+    /**
+     * Gets or creates if it doesn't exist yet the protolog datasource to use in this process.
+     * We should re-use the same datasource to avoid registering the datasource multiple times in
+     * the same process, since there is no way to unregister the datasource after registration.
+     *
+     * @return The single ProtoLog datasource instance to be shared across all ProtoLog tracing
+     *         objects.
+     */
+    public static synchronized ProtoLogDataSource getSharedSingleInstanceDataSource() {
+        if (sDataSource == null) {
+            Producer.init(InitArguments.DEFAULTS);
+            sDataSource = new ProtoLogDataSource();
+            DataSourceParams params =
+                    new DataSourceParams.Builder()
+                            .setBufferExhaustedPolicy(
+                                    DataSourceParams
+                                            .PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP)
+                            .build();
+            // NOTE: Registering that datasource is an async operation, so there may be no data
+            // traced for some messages logged right after the construction of this class.
+            sDataSource.register(params);
+        }
+
+        return sDataSource;
+    }
+
     private static void logStringMessage(LogLevel logLevel, IProtoLogGroup group,
             String stringMessage, Object... args) {
         if (sProtoLogInstance == null) {
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/core/java/com/android/internal/protolog/ProtoLogCacheUpdater.java
similarity index 61%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to core/java/com/android/internal/protolog/ProtoLogCacheUpdater.java
index 7d3d8b9..4f8655c 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/core/java/com/android/internal/protolog/ProtoLogCacheUpdater.java
@@ -13,10 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package com.android.internal.protolog;
+
+import com.android.internal.protolog.common.IProtoLog;
+
+public interface ProtoLogCacheUpdater {
+    /**
+     * Update the cache based on the latest state of the active tracing configurations.
+     *
+     * @param protoLogInstance the instance to use to query the latest state of tracing.
+     */
+    void update(IProtoLog protoLogInstance);
 }
diff --git a/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java b/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java
index e9a8770..23f7c2a 100644
--- a/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java
+++ b/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java
@@ -34,9 +34,6 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
-import android.tracing.perfetto.DataSourceParams;
-import android.tracing.perfetto.InitArguments;
-import android.tracing.perfetto.Producer;
 import android.util.Log;
 import android.util.proto.ProtoInputStream;
 import android.util.proto.ProtoOutputStream;
@@ -110,39 +107,31 @@
     private final ViewerConfigFileTracer mViewerConfigFileTracer;
 
     public ProtoLogConfigurationServiceImpl() {
-        this(ProtoLogDataSource::new, ProtoLogConfigurationServiceImpl::dumpViewerConfig);
+        this(ProtoLog.getSharedSingleInstanceDataSource(),
+                ProtoLogConfigurationServiceImpl::dumpViewerConfig);
     }
 
     @VisibleForTesting
-    public ProtoLogConfigurationServiceImpl(@NonNull ProtoLogDataSourceBuilder dataSourceBuilder) {
-        this(dataSourceBuilder, ProtoLogConfigurationServiceImpl::dumpViewerConfig);
+    public ProtoLogConfigurationServiceImpl(@NonNull ProtoLogDataSource datasource) {
+        this(datasource, ProtoLogConfigurationServiceImpl::dumpViewerConfig);
     }
 
     @VisibleForTesting
     public ProtoLogConfigurationServiceImpl(@NonNull ViewerConfigFileTracer tracer) {
-        this(ProtoLogDataSource::new, tracer);
+        this(ProtoLog.getSharedSingleInstanceDataSource(), tracer);
     }
 
     @VisibleForTesting
     public ProtoLogConfigurationServiceImpl(
-            @NonNull ProtoLogDataSourceBuilder dataSourceBuilder,
+            @NonNull ProtoLogDataSource datasource,
             @NonNull ViewerConfigFileTracer tracer) {
-        mDataSource = dataSourceBuilder.build(
-            this::onTracingInstanceStart,
-            this::onTracingInstanceFlush,
-            this::onTracingInstanceStop
-        );
-
-        // Initialize the Perfetto producer and register the Perfetto ProtoLog datasource to be
-        // receive the lifecycle callbacks of the datasource and write the viewer configs if and
-        // when required to the datasource.
-        Producer.init(InitArguments.DEFAULTS);
-        final var params = new DataSourceParams.Builder()
-                .setBufferExhaustedPolicy(DataSourceParams.PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP)
-                .build();
-        mDataSource.register(params);
-
         mViewerConfigFileTracer = tracer;
+
+        datasource.registerOnStartCallback(this::onTracingInstanceStart);
+        datasource.registerOnFlushCallback(this::onTracingInstanceFlush);
+        datasource.registerOnStopCallback(this::onTracingInstanceStop);
+
+        mDataSource = datasource;
     }
 
     public static class RegisterClientArgs extends IRegisterClientArgs.Stub {
diff --git a/core/java/com/android/internal/protolog/ProtoLogDataSource.java b/core/java/com/android/internal/protolog/ProtoLogDataSource.java
index 0afb135..ea45249 100644
--- a/core/java/com/android/internal/protolog/ProtoLogDataSource.java
+++ b/core/java/com/android/internal/protolog/ProtoLogDataSource.java
@@ -46,36 +46,30 @@
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeMap;
 
 public class ProtoLogDataSource extends DataSource<ProtoLogDataSource.Instance,
         ProtoLogDataSource.TlsState,
         ProtoLogDataSource.IncrementalState> {
     private static final String DATASOURCE_NAME = "android.protolog";
 
-    @NonNull
-    private final Instance.TracingInstanceStartCallback mOnStart;
-    @NonNull
-    private final Runnable mOnFlush;
-    @NonNull
-    private final Instance.TracingInstanceStopCallback mOnStop;
+    private final Map<Integer, ProtoLogConfig> mRunningInstances = new TreeMap<>();
 
-    public ProtoLogDataSource(
-            @NonNull Instance.TracingInstanceStartCallback onStart,
-            @NonNull Runnable onFlush,
-            @NonNull Instance.TracingInstanceStopCallback onStop) {
-        this(onStart, onFlush, onStop, DATASOURCE_NAME);
+    @NonNull
+    private final Set<Instance.TracingInstanceStartCallback> mOnStartCallbacks = new HashSet<>();
+    @NonNull
+    private final Set<Runnable> mOnFlushCallbacks = new HashSet<>();
+    @NonNull
+    private final Set<Instance.TracingInstanceStopCallback> mOnStopCallbacks = new HashSet<>();
+
+    public ProtoLogDataSource() {
+        this(DATASOURCE_NAME);
     }
 
     @VisibleForTesting
     public ProtoLogDataSource(
-            @NonNull Instance.TracingInstanceStartCallback onStart,
-            @NonNull Runnable onFlush,
-            @NonNull Instance.TracingInstanceStopCallback onStop,
             @NonNull String dataSourceName) {
         super(dataSourceName);
-        this.mOnStart = onStart;
-        this.mOnFlush = onFlush;
-        this.mOnStop = onStop;
     }
 
     @Override
@@ -106,7 +100,8 @@
         }
 
         return new Instance(
-                this, instanceIndex, config, mOnStart, mOnFlush, mOnStop);
+                this, instanceIndex, config, this::executeOnStartCallbacks,
+                this::executeOnFlushCallbacks, this::executeOnStopCallbacks);
     }
 
     @Override
@@ -128,6 +123,84 @@
         return new IncrementalState();
     }
 
+    /**
+     * Register an onStart callback that will be called when a tracing instance is started.
+     * The callback will be called immediately for all currently running tracing instances on
+     * registration.
+     * @param onStartCallback The callback to call on starting a tracing instance.
+     */
+    public synchronized void registerOnStartCallback(
+            Instance.TracingInstanceStartCallback onStartCallback) {
+        mOnStartCallbacks.add(onStartCallback);
+
+        for (var instanceIndex : mRunningInstances.keySet()) {
+            var config = mRunningInstances.get(instanceIndex);
+            onStartCallback.run(instanceIndex, config);
+        }
+    }
+
+    /**
+     * Register an onFlush callback that will be called when a tracing instance is about to flush.
+     * @param onFlushCallback The callback to call on flushing a tracing instance
+     */
+    public void registerOnFlushCallback(Runnable onFlushCallback) {
+        mOnFlushCallbacks.add(onFlushCallback);
+    }
+
+    /**
+     * Register an onStop callback that will be called when a tracing instance is being stopped.
+     * @param onStopCallback The callback to call on stopping a tracing instance.
+     */
+    public void registerOnStopCallback(Instance.TracingInstanceStopCallback onStopCallback) {
+        mOnStopCallbacks.add(onStopCallback);
+    }
+
+    /**
+     * Unregister an onStart callback.
+     * @param onStartCallback The callback object to unregister.
+     */
+    public void unregisterOnStartCallback(Instance.TracingInstanceStartCallback onStartCallback) {
+        mOnStartCallbacks.add(onStartCallback);
+    }
+
+    /**
+     * Unregister an onFlush callback.
+     * @param onFlushCallback The callback object to unregister.
+     */
+    public void unregisterOnFlushCallback(Runnable onFlushCallback) {
+        mOnFlushCallbacks.add(onFlushCallback);
+    }
+
+    /**
+     * Unregister an onStop callback.
+     * @param onStopCallback The callback object to unregister.
+     */
+    public void unregisterOnStopCallback(Instance.TracingInstanceStopCallback onStopCallback) {
+        mOnStopCallbacks.add(onStopCallback);
+    }
+
+    private synchronized void executeOnStartCallbacks(int instanceIdx, ProtoLogConfig config) {
+        mRunningInstances.put(instanceIdx, config);
+
+        for (var onStart : mOnStartCallbacks) {
+            onStart.run(instanceIdx, config);
+        }
+    }
+
+    private void executeOnFlushCallbacks() {
+        for (var onFlush : mOnFlushCallbacks) {
+            onFlush.run();
+        }
+    }
+
+    private synchronized void executeOnStopCallbacks(int instanceIdx, ProtoLogConfig config) {
+        mRunningInstances.remove(instanceIdx, config);
+
+        for (var onStop : mOnStopCallbacks) {
+            onStop.run(instanceIdx, config);
+        }
+    }
+
     public static class TlsState {
         @NonNull
         private final ProtoLogConfig mConfig;
diff --git a/core/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java
index 3378d08..c2d4b21 100644
--- a/core/java/com/android/internal/protolog/ProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java
@@ -56,7 +56,7 @@
     private static TreeMap<String, IProtoLogGroup> sLogGroups;
 
     @ProtoLogToolInjected(CACHE_UPDATER)
-    private static Runnable sCacheUpdater;
+    private static ProtoLogCacheUpdater sCacheUpdater;
 
     /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
     public static void d(IProtoLogGroup group, long messageHash, int paramsMask, Object... args) {
@@ -93,7 +93,12 @@
      * and log level.
      */
     public static boolean isEnabled(IProtoLogGroup group, LogLevel level) {
-        return getSingleInstance().isEnabled(group, level);
+        return isEnabled(getSingleInstance(), group, level);
+    }
+
+    private static boolean isEnabled(
+            IProtoLog protoLogInstance, IProtoLogGroup group, LogLevel level) {
+        return protoLogInstance.isEnabled(group, level);
     }
 
     /**
@@ -106,36 +111,37 @@
 
             final var groups = sLogGroups.values().toArray(new IProtoLogGroup[0]);
             if (android.tracing.Flags.perfettoProtologTracing()) {
-                sServiceInstance = createProtoLogImpl(groups);
+                var viewerConfigFile = new File(sViewerConfigPath);
+                if (!viewerConfigFile.exists()) {
+                    // TODO(b/353530422): Remove - temporary fix to unblock b/352290057
+                    // In robolectric tests the viewer config file isn't current available, so we
+                    // cannot use the ProcessedPerfettoProtoLogImpl.
+                    Log.e(LOG_TAG, "Failed to find viewer config file " + sViewerConfigPath
+                            + " when setting up " + ProtoLogImpl.class.getSimpleName() + ". "
+                            + "ProtoLog will not work here!");
+
+                    sServiceInstance = new NoViewerConfigProtoLogImpl();
+                } else {
+                    var datasource = ProtoLog.getSharedSingleInstanceDataSource();
+                    try {
+                        var processedProtoLogImpl =
+                                new ProcessedPerfettoProtoLogImpl(datasource, sViewerConfigPath,
+                                        sCacheUpdater, groups);
+                        sServiceInstance = processedProtoLogImpl;
+                        processedProtoLogImpl.enable();
+                    } catch (ServiceManager.ServiceNotFoundException e) {
+                        throw new RuntimeException(e);
+                    }
+                }
             } else {
                 sServiceInstance = createLegacyProtoLogImpl(groups);
             }
 
-            sCacheUpdater.run();
+            sCacheUpdater.update(sServiceInstance);
         }
         return sServiceInstance;
     }
 
-    private static IProtoLog createProtoLogImpl(IProtoLogGroup[] groups) {
-        try {
-            File f = new File(sViewerConfigPath);
-            if (!f.exists()) {
-                // TODO(b/353530422): Remove - temporary fix to unblock b/352290057
-                // In robolectric tests the viewer config file isn't current available, so we cannot
-                // use the ProcessedPerfettoProtoLogImpl.
-                Log.e(LOG_TAG, "Failed to find viewer config file " + sViewerConfigPath
-                        + " when setting up " + ProtoLogImpl.class.getSimpleName() + ". "
-                        + "ProtoLog will not work here!");
-
-                return new NoViewerConfigProtoLogImpl();
-            } else {
-                return new ProcessedPerfettoProtoLogImpl(sViewerConfigPath, sCacheUpdater, groups);
-            }
-        } catch (ServiceManager.ServiceNotFoundException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
     private static LegacyProtoLogImpl createLegacyProtoLogImpl(IProtoLogGroup[] groups) {
         var protologImpl = new LegacyProtoLogImpl(
                 sLegacyOutputFilePath, sLegacyViewerConfigPath, sCacheUpdater);
diff --git a/core/java/com/android/internal/protolog/UnprocessedPerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/UnprocessedPerfettoProtoLogImpl.java
index f3fe580..ebb07a04 100644
--- a/core/java/com/android/internal/protolog/UnprocessedPerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/UnprocessedPerfettoProtoLogImpl.java
@@ -23,14 +23,10 @@
 import com.android.internal.protolog.common.IProtoLogGroup;
 
 public class UnprocessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl {
-    public UnprocessedPerfettoProtoLogImpl(@NonNull IProtoLogGroup[] groups)
+    public UnprocessedPerfettoProtoLogImpl(
+            @NonNull ProtoLogDataSource dataSource, @NonNull IProtoLogGroup[] groups)
             throws ServiceManager.ServiceNotFoundException {
-        this(() -> {}, groups);
-    }
-
-    public UnprocessedPerfettoProtoLogImpl(@NonNull Runnable cacheUpdater,
-            @NonNull IProtoLogGroup[] groups) throws ServiceManager.ServiceNotFoundException {
-        super(cacheUpdater, groups);
+        super(dataSource, (instance) -> {}, groups);
         readyToLogToLogcat();
     }
 
diff --git a/core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java b/core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java
index 862f7cb..5eedec6 100644
--- a/core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java
+++ b/core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java
@@ -17,6 +17,7 @@
 package com.android.internal.vibrator.persistence;
 
 import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_DELAY_MS;
+import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_DELAY_TYPE;
 import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_NAME;
 import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_SCALE;
 import static com.android.internal.vibrator.persistence.XmlConstants.NAMESPACE;
@@ -25,9 +26,11 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.VibrationEffect;
+import android.os.vibrator.Flags;
 import android.os.vibrator.PrimitiveSegment;
 
 import com.android.internal.vibrator.persistence.SerializedComposedEffect.SerializedSegment;
+import com.android.internal.vibrator.persistence.XmlConstants.PrimitiveDelayType;
 import com.android.internal.vibrator.persistence.XmlConstants.PrimitiveEffectName;
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
@@ -46,17 +49,26 @@
     private final PrimitiveEffectName mPrimitiveName;
     private final float mPrimitiveScale;
     private final int mPrimitiveDelayMs;
+    @Nullable
+    private final PrimitiveDelayType mDelayType;
 
-    SerializedCompositionPrimitive(PrimitiveEffectName primitiveName, float scale, int delayMs) {
+    SerializedCompositionPrimitive(PrimitiveEffectName primitiveName, float scale, int delayMs,
+            @Nullable PrimitiveDelayType delayType) {
         mPrimitiveName = primitiveName;
         mPrimitiveScale = scale;
         mPrimitiveDelayMs = delayMs;
+        mDelayType = delayType;
     }
 
     @Override
     public void deserializeIntoComposition(@NonNull VibrationEffect.Composition composition) {
-        composition.addPrimitive(mPrimitiveName.getPrimitiveId(), mPrimitiveScale,
-                mPrimitiveDelayMs);
+        if (Flags.primitiveCompositionAbsoluteDelay() && mDelayType != null) {
+            composition.addPrimitive(mPrimitiveName.getPrimitiveId(), mPrimitiveScale,
+                    mPrimitiveDelayMs, mDelayType.getDelayType());
+        } else {
+            composition.addPrimitive(mPrimitiveName.getPrimitiveId(), mPrimitiveScale,
+                    mPrimitiveDelayMs);
+        }
     }
 
     @Override
@@ -72,6 +84,12 @@
             serializer.attributeInt(NAMESPACE, ATTRIBUTE_DELAY_MS, mPrimitiveDelayMs);
         }
 
+        if (Flags.primitiveCompositionAbsoluteDelay() && mDelayType != null) {
+            if (mDelayType.getDelayType() != PrimitiveSegment.DEFAULT_DELAY_TYPE) {
+                serializer.attribute(NAMESPACE, ATTRIBUTE_DELAY_TYPE, mDelayType.toString());
+            }
+        }
+
         serializer.endTag(NAMESPACE, TAG_PRIMITIVE_EFFECT);
     }
 
@@ -81,6 +99,7 @@
                 + "name=" + mPrimitiveName
                 + ", scale=" + mPrimitiveScale
                 + ", delayMs=" + mPrimitiveDelayMs
+                + ", delayType=" + mDelayType
                 + '}';
     }
 
@@ -91,8 +110,14 @@
         static SerializedCompositionPrimitive parseNext(@NonNull TypedXmlPullParser parser)
                 throws XmlParserException, IOException {
             XmlValidator.checkStartTag(parser, TAG_PRIMITIVE_EFFECT);
-            XmlValidator.checkTagHasNoUnexpectedAttributes(parser,
-                    ATTRIBUTE_NAME, ATTRIBUTE_DELAY_MS, ATTRIBUTE_SCALE);
+
+            if (Flags.primitiveCompositionAbsoluteDelay()) {
+                XmlValidator.checkTagHasNoUnexpectedAttributes(parser,
+                        ATTRIBUTE_NAME, ATTRIBUTE_DELAY_MS, ATTRIBUTE_SCALE, ATTRIBUTE_DELAY_TYPE);
+            } else {
+                XmlValidator.checkTagHasNoUnexpectedAttributes(parser,
+                        ATTRIBUTE_NAME, ATTRIBUTE_DELAY_MS, ATTRIBUTE_SCALE);
+            }
 
             PrimitiveEffectName primitiveName = parsePrimitiveName(
                     parser.getAttributeValue(NAMESPACE, ATTRIBUTE_NAME));
@@ -100,11 +125,13 @@
                     parser, ATTRIBUTE_SCALE, 0, 1, PrimitiveSegment.DEFAULT_SCALE);
             int delayMs = XmlReader.readAttributeIntNonNegative(
                     parser, ATTRIBUTE_DELAY_MS, PrimitiveSegment.DEFAULT_DELAY_MILLIS);
+            PrimitiveDelayType delayType = parseDelayType(
+                    parser.getAttributeValue(NAMESPACE, ATTRIBUTE_DELAY_TYPE));
 
             // Consume tag
             XmlReader.readEndTag(parser);
 
-            return new SerializedCompositionPrimitive(primitiveName, scale, delayMs);
+            return new SerializedCompositionPrimitive(primitiveName, scale, delayMs, delayType);
         }
 
         @NonNull
@@ -119,5 +146,21 @@
             }
             return effectName;
         }
+
+        @Nullable
+        private static PrimitiveDelayType parseDelayType(@Nullable String name)
+                throws XmlParserException {
+            if (name == null) {
+                return null;
+            }
+            if (!Flags.primitiveCompositionAbsoluteDelay()) {
+                throw new XmlParserException("Unexpected primitive delay type " + name);
+            }
+            PrimitiveDelayType delayType = PrimitiveDelayType.findByName(name);
+            if (delayType == null) {
+                throw new XmlParserException("Unexpected primitive delay type " + name);
+            }
+            return delayType;
+        }
     }
 }
diff --git a/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java b/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java
index d74a23d..cb834a5 100644
--- a/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java
+++ b/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java
@@ -27,6 +27,7 @@
 
 import com.android.internal.vibrator.persistence.SerializedComposedEffect.SerializedSegment;
 import com.android.internal.vibrator.persistence.XmlConstants.PredefinedEffectName;
+import com.android.internal.vibrator.persistence.XmlConstants.PrimitiveDelayType;
 import com.android.internal.vibrator.persistence.XmlConstants.PrimitiveEffectName;
 
 import java.util.List;
@@ -170,8 +171,20 @@
         XmlValidator.checkSerializerCondition(primitiveName != null,
                 "Unsupported primitive effect id %s", primitive.getPrimitiveId());
 
+        PrimitiveDelayType delayType = null;
+
+        if (Flags.primitiveCompositionAbsoluteDelay()) {
+            delayType = PrimitiveDelayType.findByType(primitive.getDelayType());
+            XmlValidator.checkSerializerCondition(delayType != null,
+                    "Unsupported primitive delay type %s", primitive.getDelayType());
+        } else {
+            XmlValidator.checkSerializerCondition(
+                    primitive.getDelayType() == PrimitiveSegment.DEFAULT_DELAY_TYPE,
+                    "Unsupported primitive delay type %s", primitive.getDelayType());
+        }
+
         return new SerializedCompositionPrimitive(
-                primitiveName, primitive.getScale(), primitive.getDelay());
+                primitiveName, primitive.getScale(), primitive.getDelay(), delayType);
     }
 
     private static int toAmplitudeInt(float amplitude) {
diff --git a/core/java/com/android/internal/vibrator/persistence/XmlConstants.java b/core/java/com/android/internal/vibrator/persistence/XmlConstants.java
index 2a55d99..4122215 100644
--- a/core/java/com/android/internal/vibrator/persistence/XmlConstants.java
+++ b/core/java/com/android/internal/vibrator/persistence/XmlConstants.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.VibrationEffect;
+import android.os.VibrationEffect.Composition.DelayType;
 import android.os.VibrationEffect.Composition.PrimitiveType;
 
 import java.lang.annotation.Retention;
@@ -51,6 +52,7 @@
     public static final String ATTRIBUTE_AMPLITUDE = "amplitude";
     public static final String ATTRIBUTE_SCALE = "scale";
     public static final String ATTRIBUTE_DELAY_MS = "delayMs";
+    public static final String ATTRIBUTE_DELAY_TYPE = "delayType";
 
     public static final String VALUE_AMPLITUDE_DEFAULT = "default";
 
@@ -87,7 +89,7 @@
 
         /**
          * Return the {@link PrimitiveEffectName} that represents given primitive id, or null if
-         * none of the available names maps to the given id.
+         * none of the available names map to the given id.
          */
         @Nullable
         public static PrimitiveEffectName findById(int primitiveId) {
@@ -200,4 +202,53 @@
             return name().toLowerCase(Locale.ROOT);
         }
     }
+
+    /** Represent supported values for attribute delay type in {@link #TAG_PRIMITIVE_EFFECT}  */
+    public enum PrimitiveDelayType {
+        PAUSE(VibrationEffect.Composition.DELAY_TYPE_PAUSE),
+        RELATIVE_START_OFFSET(VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET);
+
+        @DelayType private final int mDelayType;
+
+        PrimitiveDelayType(@DelayType int type) {
+            mDelayType = type;
+        }
+
+        /**
+         * Return the {@link PrimitiveEffectName} that represents given primitive id, or null if
+         * none of the available names maps to the given id.
+         */
+        @Nullable
+        public static PrimitiveDelayType findByType(int delayType) {
+            for (PrimitiveDelayType type : PrimitiveDelayType.values()) {
+                if (type.mDelayType == delayType) {
+                    return type;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Return the {@link PrimitiveEffectName} that represents given primitive name, or null if
+         * none of the available names maps to the given name.
+         */
+        @Nullable
+        public static PrimitiveDelayType findByName(@NonNull String delayType) {
+            try {
+                return PrimitiveDelayType.valueOf(delayType.toUpperCase(Locale.ROOT));
+            } catch (IllegalArgumentException e) {
+                return null;
+            }
+        }
+
+        @DelayType
+        public int getDelayType() {
+            return mDelayType;
+        }
+
+        @Override
+        public String toString() {
+            return name().toLowerCase(Locale.ROOT);
+        }
+    }
 }
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 2bfbf84..4b90420 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.widget;
 
+import static android.app.Flags.notificationsRedesignTemplates;
 import static android.widget.flags.Flags.conversationLayoutUseMaximumChildHeight;
 
 import static com.android.internal.widget.MessagingGroup.IMAGE_DISPLAY_LOCATION_EXTERNAL;
@@ -692,7 +693,7 @@
     }
 
     private void updateActionListPadding() {
-        if (mActions != null) {
+        if (!notificationsRedesignTemplates() && mActions != null) {
             mActions.setCollapsibleIndentDimen(R.dimen.call_notification_collapsible_indent);
         }
     }
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index 97a2d3b..4305ba7 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -261,7 +261,7 @@
         MessagingGroup createdGroup = sInstancePool.acquire();
         if (createdGroup == null) {
             createdGroup = (MessagingGroup) LayoutInflater.from(layout.getContext()).inflate(
-                    R.layout.notification_template_messaging_group, layout,
+                    getMessagingGroupLayoutResource(), layout,
                     false);
             createdGroup.addOnLayoutChangeListener(MessagingLayout.MESSAGING_PROPERTY_ANIMATOR);
         }
@@ -269,6 +269,14 @@
         return createdGroup;
     }
 
+    private static int getMessagingGroupLayoutResource() {
+        if (Flags.notificationsRedesignTemplates()) {
+            return R.layout.notification_2025_messaging_group;
+        } else {
+            return R.layout.notification_template_messaging_group;
+        }
+    }
+
     public void removeMessage(MessagingMessage messagingMessage,
             ArrayList<MessagingLinearLayout.MessagingChild> toRecycle) {
         View view = messagingMessage.getView();
diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java
index 301dc39..cac2024 100644
--- a/core/java/com/android/internal/widget/NotificationActionListLayout.java
+++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java
@@ -20,6 +20,7 @@
 import static android.app.Flags.evenlyDividedCallStyleActionLayout;
 
 import android.annotation.DimenRes;
+import android.app.Flags;
 import android.app.Notification;
 import android.content.Context;
 import android.content.res.TypedArray;
@@ -58,7 +59,7 @@
     private int mEmphasizedPaddingBottom;
     private int mEmphasizedHeight;
     private int mRegularHeight;
-    @DimenRes private int mCollapsibleIndentDimen = R.dimen.notification_actions_padding_start;
+    @DimenRes private int mCollapsibleIndentDimen;
     int mNumNotGoneChildren;
     int mNumPriorityChildren;
 
@@ -73,6 +74,10 @@
     public NotificationActionListLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
+        mCollapsibleIndentDimen = Flags.notificationsRedesignTemplates()
+                ? R.dimen.notification_2025_actions_margin_start
+                : R.dimen.notification_actions_padding_start;
+
         int[] attrIds = { android.R.attr.gravity };
         TypedArray ta = context.obtainStyledAttributes(attrs, attrIds, defStyleAttr, defStyleRes);
         mGravity = ta.getInt(0, 0);
diff --git a/core/java/com/android/internal/widget/NotificationProgressBar.java b/core/java/com/android/internal/widget/NotificationProgressBar.java
index 7a21275..8cd7843 100644
--- a/core/java/com/android/internal/widget/NotificationProgressBar.java
+++ b/core/java/com/android/internal/widget/NotificationProgressBar.java
@@ -68,12 +68,18 @@
 
     @Nullable
     private Drawable mTracker = null;
+
+    /** @see R.styleable#NotificationProgressBar_trackerHeight */
     private final int mTrackerHeight;
     private int mTrackerWidth;
     private int mTrackerPos;
     private final Matrix mMatrix = new Matrix();
     private Matrix mTrackerDrawMatrix = null;
 
+    private float mScale = 0;
+    /** Indicates whether mTrackerPos needs to be recalculated before the tracker is drawn. */
+    private boolean mTrackerPosIsDirty = false;
+
     public NotificationProgressBar(Context context) {
         this(context, null);
     }
@@ -107,8 +113,8 @@
         final Drawable tracker = a.getDrawable(R.styleable.NotificationProgressBar_tracker);
         setTracker(tracker);
 
-        // If this is configured to be non-zero, will scale the tracker drawable and ensure its
-        // aspect ration is between 2:1 to 1:2.
+        // If this is configured to be a non-zero size, will scale and crop the tracker drawable to
+        // ensure its aspect ratio is between 2:1 to 1:2.
         mTrackerHeight = a.getDimensionPixelSize(R.styleable.NotificationProgressBar_trackerHeight,
                 0);
     }
@@ -200,8 +206,9 @@
     }
 
     private void setTracker(@Nullable Drawable tracker) {
-        final boolean needUpdate = mTracker != null && tracker != mTracker;
-        if (needUpdate) {
+        if (tracker == mTracker) return;
+
+        if (mTracker != null) {
             mTracker.setCallback(null);
         }
 
@@ -214,33 +221,41 @@
             if (canResolveLayoutDirection()) {
                 tracker.setLayoutDirection(getLayoutDirection());
             }
-
-            // If we're updating get the new states
-            if (needUpdate && (tracker.getIntrinsicWidth() != mTracker.getIntrinsicWidth()
-                    || tracker.getIntrinsicHeight() != mTracker.getIntrinsicHeight())) {
-                requestLayout();
-            }
         }
 
+        final boolean trackerSizeChanged = trackerSizeChanged(tracker, mTracker);
+
         mTracker = tracker;
         if (mNotificationProgressDrawable != null) {
             mNotificationProgressDrawable.setHasTrackerIcon(mTracker != null);
         }
 
         configureTrackerBounds();
+        updateTrackerAndBarPos(getWidth(), getHeight());
+
+        // Change in tracker size may lead to change in measured view size.
+        // @see #onMeasure.
+        if (trackerSizeChanged) requestLayout();
 
         invalidate();
 
-        if (needUpdate) {
-            updateTrackerAndBarPos(getWidth(), getHeight());
-            if (tracker != null && tracker.isStateful()) {
-                // Note that if the states are different this won't work.
-                // For now, let's consider that an app bug.
-                tracker.setState(getDrawableState());
-            }
+        if (tracker != null && tracker.isStateful()) {
+            // Note that if the states are different this won't work.
+            // For now, let's consider that an app bug.
+            tracker.setState(getDrawableState());
         }
     }
 
+    private static boolean trackerSizeChanged(@Nullable Drawable newTracker,
+            @Nullable Drawable oldTracker) {
+        if (newTracker == null && oldTracker == null) return false;
+        if (newTracker == null && oldTracker != null) return true;
+        if (newTracker != null && oldTracker == null) return true;
+
+        return newTracker.getIntrinsicWidth() != oldTracker.getIntrinsicWidth()
+                || newTracker.getIntrinsicHeight() != oldTracker.getIntrinsicHeight();
+    }
+
     private void configureTrackerBounds() {
         // Reset the tracker draw matrix to null
         mTrackerDrawMatrix = null;
@@ -279,6 +294,44 @@
     }
 
     @Override
+    public synchronized void setProgress(int progress) {
+        super.setProgress(progress);
+
+        onMaybeVisualProgressChanged();
+    }
+
+    @Override
+    public void setProgress(int progress, boolean animate) {
+        // Animation isn't supported by NotificationProgressBar.
+        super.setProgress(progress, false);
+
+        onMaybeVisualProgressChanged();
+    }
+
+    @Override
+    public synchronized void setMin(int min) {
+        super.setMin(min);
+
+        onMaybeVisualProgressChanged();
+    }
+
+    @Override
+    public synchronized void setMax(int max) {
+        super.setMax(max);
+
+        onMaybeVisualProgressChanged();
+    }
+
+    private void onMaybeVisualProgressChanged() {
+        float scale = getScale();
+        if (mScale == scale) return;
+
+        mScale = scale;
+        mTrackerPosIsDirty = true;
+        invalidate();
+    }
+
+    @Override
     protected boolean verifyDrawable(@NonNull Drawable who) {
         return who == mTracker || super.verifyDrawable(who);
     }
@@ -328,7 +381,7 @@
         // parameter does.
         final int barHeight = Math.min(getMaxHeight(), paddedHeight);
         final int trackerHeight = tracker == null ? 0
-                : ((mTrackerHeight == 0) ? tracker.getIntrinsicHeight() : mTrackerHeight);
+                : ((mTrackerHeight <= 0) ? tracker.getIntrinsicHeight() : mTrackerHeight);
 
         // Apply offset to whichever item is taller.
         final int barOffsetY;
@@ -349,7 +402,7 @@
         }
 
         if (tracker != null) {
-            setTrackerPos(w, tracker, getScale(), trackerOffsetY);
+            setTrackerPos(w, tracker, mScale, trackerOffsetY);
         }
     }
 
@@ -373,7 +426,7 @@
         int available = w - mPaddingLeft - mPaddingRight;
         final int trackerWidth = tracker.getIntrinsicWidth();
         final int trackerHeight = tracker.getIntrinsicHeight();
-        available -= ((mTrackerHeight == 0) ? trackerWidth : mTrackerWidth);
+        available -= ((mTrackerHeight <= 0) ? trackerWidth : mTrackerWidth);
 
         final int trackerPos = (int) (scale * available + 0.5f);
 
@@ -401,6 +454,8 @@
 
         // Canvas will be translated, so 0,0 is where we start drawing
         tracker.setBounds(left, top, right, bottom);
+
+        mTrackerPosIsDirty = false;
     }
 
     @Override
@@ -424,18 +479,26 @@
      * Draw the tracker.
      */
     private void drawTracker(Canvas canvas) {
-        if (mTracker != null) {
-            final int saveCount = canvas.save();
-            // Translate the canvas origin to tracker position to make the draw matrix and the RtL
-            // transformations work.
-            canvas.translate(mPaddingLeft + mTrackerPos, mPaddingTop);
-            canvas.clipRect(0, 0, mTrackerWidth, mTrackerHeight);
-            if (mTrackerDrawMatrix != null) {
-                canvas.concat(mTrackerDrawMatrix);
-            }
-            mTracker.draw(canvas);
-            canvas.restoreToCount(saveCount);
+        if (mTracker == null) return;
+
+        if (mTrackerPosIsDirty) {
+            setTrackerPos(getWidth(), mTracker, mScale, Integer.MIN_VALUE);
         }
+
+        final int saveCount = canvas.save();
+        // Translate the canvas origin to tracker position to make the draw matrix and the RtL
+        // transformations work.
+        canvas.translate(mPaddingLeft + mTrackerPos, mPaddingTop);
+
+        if (mTrackerHeight > 0) {
+            canvas.clipRect(0, 0, mTrackerWidth, mTrackerHeight);
+        }
+
+        if (mTrackerDrawMatrix != null) {
+            canvas.concat(mTrackerDrawMatrix);
+        }
+        mTracker.draw(canvas);
+        canvas.restoreToCount(saveCount);
     }
 
     @Override
@@ -468,7 +531,7 @@
 
         final Drawable tracker = mTracker;
         if (tracker != null) {
-            setTrackerPos(getWidth(), tracker, getScale(), Integer.MIN_VALUE);
+            setTrackerPos(getWidth(), tracker, mScale, Integer.MIN_VALUE);
 
             // Since we draw translated, the drawable's bounds that it signals
             // for invalidation won't be the actual bounds we want invalidated,
diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operation.java b/core/java/com/android/internal/widget/remotecompose/core/Operation.java
index 102003e..6f6a0a8 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/Operation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/Operation.java
@@ -18,19 +18,19 @@
 import android.annotation.NonNull;
 
 /** Base interface for RemoteCompose operations */
-public interface Operation {
+public abstract class Operation {
 
     /** add the operation to the buffer */
-    void write(@NonNull WireBuffer buffer);
+    public abstract void write(@NonNull WireBuffer buffer);
 
     /**
      * paint an operation
      *
      * @param context the paint context used to paint the operation
      */
-    void apply(@NonNull RemoteContext context);
+    public abstract void apply(@NonNull RemoteContext context);
 
     /** Debug utility to display an operation + indentation */
     @NonNull
-    String deepToString(@NonNull String indent);
+    public abstract String deepToString(@NonNull String indent);
 }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/OperationInterface.java b/core/java/com/android/internal/widget/remotecompose/core/OperationInterface.java
new file mode 100644
index 0000000..741303a
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/OperationInterface.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core;
+
+import android.annotation.NonNull;
+
+/** Base interface for RemoteCompose operations */
+public interface OperationInterface {
+
+    /** add the operation to the buffer */
+    void write(@NonNull WireBuffer buffer);
+
+    /**
+     * paint an operation
+     *
+     * @param context the paint context used to paint the operation
+     */
+    void apply(@NonNull RemoteContext context);
+
+    /** Debug utility to display an operation + indentation */
+    @NonNull
+    String deepToString(@NonNull String indent);
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operations.java b/core/java/com/android/internal/widget/remotecompose/core/Operations.java
index 687a99b..006fe3a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/Operations.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/Operations.java
@@ -55,7 +55,10 @@
 import com.android.internal.widget.remotecompose.core.operations.MatrixTranslate;
 import com.android.internal.widget.remotecompose.core.operations.NamedVariable;
 import com.android.internal.widget.remotecompose.core.operations.PaintData;
+import com.android.internal.widget.remotecompose.core.operations.PathAppend;
+import com.android.internal.widget.remotecompose.core.operations.PathCreate;
 import com.android.internal.widget.remotecompose.core.operations.PathData;
+import com.android.internal.widget.remotecompose.core.operations.PathTween;
 import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior;
 import com.android.internal.widget.remotecompose.core.operations.RootContentDescription;
 import com.android.internal.widget.remotecompose.core.operations.ShaderData;
@@ -178,6 +181,9 @@
     public static final int TEXT_MEASURE = 155;
     public static final int TEXT_LENGTH = 156;
     public static final int TOUCH_EXPRESSION = 157;
+    public static final int PATH_TWEEN = 158;
+    public static final int PATH_CREATE = 159;
+    public static final int PATH_ADD = 160;
 
     ///////////////////////////////////////// ======================
 
@@ -353,5 +359,8 @@
         map.put(TEXT_MEASURE, TextMeasure::read);
         map.put(TEXT_LENGTH, TextLength::read);
         map.put(TOUCH_EXPRESSION, TouchExpression::read);
+        map.put(PATH_TWEEN, PathTween::read);
+        map.put(PATH_CREATE, PathCreate::read);
+        map.put(PATH_ADD, PathAppend::read);
     }
 }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
index 38b08e9..7ecd118 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
@@ -157,6 +157,8 @@
     public abstract void drawTweenPath(
             int path1Id, int path2Id, float tween, float start, float stop);
 
+    public abstract void tweenPath(int out, int path1, int path2, float tween);
+
     /**
      * This applies changes to the current paint
      *
diff --git a/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java b/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java
index 9999182..cfdd522 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java
@@ -21,7 +21,7 @@
  * PaintOperation interface, used for operations aimed at painting (while any operation _can_ paint,
  * this make it a little more explicit)
  */
-public abstract class PaintOperation implements Operation {
+public abstract class PaintOperation extends Operation {
 
     @Override
     public void apply(@NonNull RemoteContext context) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
index c05079e..3a5d68d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
@@ -59,7 +59,10 @@
 import com.android.internal.widget.remotecompose.core.operations.MatrixTranslate;
 import com.android.internal.widget.remotecompose.core.operations.NamedVariable;
 import com.android.internal.widget.remotecompose.core.operations.PaintData;
+import com.android.internal.widget.remotecompose.core.operations.PathAppend;
+import com.android.internal.widget.remotecompose.core.operations.PathCreate;
 import com.android.internal.widget.remotecompose.core.operations.PathData;
+import com.android.internal.widget.remotecompose.core.operations.PathTween;
 import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior;
 import com.android.internal.widget.remotecompose.core.operations.RootContentDescription;
 import com.android.internal.widget.remotecompose.core.operations.TextData;
@@ -644,6 +647,37 @@
     }
 
     /**
+     * interpolate the two paths to produce a 3rd
+     *
+     * @param pid1 the first path
+     * @param pid2 the second path
+     * @param tween path is the path1+(pat2-path1)*tween
+     * @return id of the tweened path
+     */
+    public int pathTween(int pid1, int pid2, float tween) {
+        int out = mRemoteComposeState.nextId();
+        PathTween.apply(mBuffer, out, pid1, pid2, tween);
+        return out;
+    }
+
+    /**
+     * Create a path with an initial moveTo
+     *
+     * @param x x coordinate of the moveto
+     * @param y y coordinate of the moveto
+     * @return id of the created path
+     */
+    public int pathCreate(float x, float y) {
+        int out = mRemoteComposeState.nextId();
+        PathCreate.apply(mBuffer, out, x, y);
+        return out;
+    }
+
+    public void pathAppend(int id, float... path) {
+        PathAppend.apply(mBuffer, id, path);
+    }
+
+    /**
      * Draw the specified path
      *
      * @param pathId
@@ -1154,6 +1188,16 @@
     }
 
     /**
+     * Reserve a float and returns a NaN number pointing to that float
+     *
+     * @return the nan id of float
+     */
+    public float reserveFloatVariable() {
+        int id = mRemoteComposeState.cacheFloat(0f);
+        return Utils.asNan(id);
+    }
+
+    /**
      * Add a Integer return an id number pointing to that float.
      *
      * @param value adds an integer and assigns it an id
@@ -1651,8 +1695,8 @@
      */
     public void addModifierScroll(int direction, float positionId, int notches) {
         // TODO: add support for non-notch behaviors etc.
-        float max = this.addFloat(0f);
-        float notchMax = this.addFloat(0f);
+        float max = this.reserveFloatVariable();
+        float notchMax = this.reserveFloatVariable();
         float touchExpressionDirection =
                 direction != 0 ? RemoteContext.FLOAT_TOUCH_POS_X : RemoteContext.FLOAT_TOUCH_POS_Y;
         this.addTouchExpression(
@@ -1807,8 +1851,8 @@
         ClipRectModifierOperation.apply(mBuffer);
     }
 
-    public void addLoopStart(float count, float from, float step, int indexId) {
-        LoopOperation.apply(mBuffer, count, from, step, indexId);
+    public void addLoopStart(int indexId, float from, float step, float until) {
+        LoopOperation.apply(mBuffer, indexId, from, step, until);
     }
 
     public void addLoopEnd() {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeOperation.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeOperation.java
index e60695f..97487e6 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeOperation.java
@@ -15,4 +15,4 @@
  */
 package com.android.internal.widget.remotecompose.core;
 
-public interface RemoteComposeOperation extends Operation {}
+public interface RemoteComposeOperation {}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
index a903e6e..f5f9e21 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
@@ -131,6 +131,16 @@
         }
     }
 
+    private final IntMap<float[]> mPathData = new IntMap<>();
+
+    public void putPathData(int id, float[] data) {
+        mPathData.put(id, data);
+    }
+
+    public float[] getPathData(int id) {
+        return mPathData.get(id);
+    }
+
     /**
      * Adds a data Override.
      *
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
index 26305bf..6eb8463 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
@@ -93,12 +93,20 @@
     /**
      * Load a path under an id. Paths can be use in clip drawPath and drawTweenPath
      *
-     * @param instanceId
-     * @param floatPath
+     * @param instanceId the id to save this path under
+     * @param floatPath the path as a float array
      */
     public abstract void loadPathData(int instanceId, @NonNull float[] floatPath);
 
     /**
+     * Load a path under an id. Paths can be use in clip drawPath and drawTweenPath
+     *
+     * @param instanceId
+     * @return the a
+     */
+    public abstract @Nullable float[] getPathData(int instanceId);
+
+    /**
      * Associate a name with a give id.
      *
      * @param varName the name
diff --git a/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java
index a64b706..2f1502c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java
@@ -28,11 +28,17 @@
     int mStartingIndex = 0;
     int mSize = 0;
 
+    /**
+     * Create a wire buffer
+     *
+     * @param size the initial size of the buffer
+     */
     public WireBuffer(int size) {
         mMaxSize = size;
         mBuffer = new byte[mMaxSize];
     }
 
+    /** Create a wire buffer of default size */
     public WireBuffer() {
         this(BUFFER_SIZE);
     }
@@ -44,37 +50,74 @@
         }
     }
 
+    /**
+     * get the wire buffer's underlying byte array. Note the array will be bigger that the used
+     * portion
+     *
+     * @return byte array of the wire buffer
+     */
     public @NonNull byte[] getBuffer() {
         return mBuffer;
     }
 
+    /**
+     * The current mix size of the buffer
+     *
+     * @return max size
+     */
     public int getMax_size() {
         return mMaxSize;
     }
 
+    /**
+     * The current point in the buffer which will be written to
+     *
+     * @return index pointing into the buffer
+     */
     public int getIndex() {
         return mIndex;
     }
 
+    /**
+     * The size of the buffer
+     *
+     * @return the size of the buffer
+     */
     public int getSize() {
         return mSize;
     }
 
+    /**
+     * Reposition the pointer
+     *
+     * @param index the new position of the index
+     */
     public void setIndex(int index) {
         this.mIndex = index;
     }
 
+    /**
+     * Write a byte representing the command into the buffer
+     *
+     * @param type the command id
+     */
     public void start(int type) {
         mStartingIndex = mIndex;
         writeByte(type);
     }
 
+    /**
+     * Unused Todo remove?
+     *
+     * @param type the type of object to write
+     */
     public void startWithSize(int type) {
         mStartingIndex = mIndex;
         writeByte(type);
         mIndex += 4; // skip ahead for the future size
     }
 
+    /** Unused Todo remove? */
     public void endWithSize() {
         int size = mIndex - mStartingIndex;
         int currentIndex = mIndex;
@@ -97,10 +140,20 @@
         }
     }
 
+    /**
+     * return the size of the buffer todo rename to getSize
+     *
+     * @return the size of the buffer
+     */
     public int size() {
         return mSize;
     }
 
+    /**
+     * Bytes available
+     *
+     * @return the size - index
+     */
     public boolean available() {
         return mSize - mIndex > 0;
     }
@@ -109,28 +162,53 @@
     // Read values
     ///////////////////////////////////////////////////////////////////////////
 
+    /**
+     * read the operation type (reads a single byte)
+     *
+     * @return the byte cast to an integer
+     */
     public int readOperationType() {
         return readByte();
     }
 
+    /**
+     * Read a boolean (stored as a byte 1 = true)
+     *
+     * @return boolean of the byte
+     */
     public boolean readBoolean() {
         byte value = mBuffer[mIndex];
         mIndex++;
         return (value == 1);
     }
 
+    /**
+     * read a single byte byte
+     *
+     * @return byte from 0..255 as an Integer
+     */
     public int readByte() {
         int value = 0xFF & mBuffer[mIndex];
         mIndex++;
         return value;
     }
 
+    /**
+     * read a short [byte n] << 8 | [byte n+1]; index increast by 2
+     *
+     * @return return a short cast as an integer
+     */
     public int readShort() {
         int v1 = (mBuffer[mIndex++] & 0xFF) << 8;
         int v2 = (mBuffer[mIndex++] & 0xFF) << 0;
         return v1 + v2;
     }
 
+    /**
+     * Read an integer without incrementing the index
+     *
+     * @return the integer
+     */
     public int peekInt() {
         int tmp = mIndex;
         int v1 = (mBuffer[tmp++] & 0xFF) << 24;
@@ -140,6 +218,11 @@
         return v1 + v2 + v3 + v4;
     }
 
+    /**
+     * Read an integer. index increased by 4
+     *
+     * @return integer
+     */
     public int readInt() {
         int v1 = (mBuffer[mIndex++] & 0xFF) << 24;
         int v2 = (mBuffer[mIndex++] & 0xFF) << 16;
@@ -148,6 +231,11 @@
         return v1 + v2 + v3 + v4;
     }
 
+    /**
+     * Read a long index is increased by 8
+     *
+     * @return long
+     */
     public long readLong() {
         long v1 = (mBuffer[mIndex++] & 0xFFL) << 56;
         long v2 = (mBuffer[mIndex++] & 0xFFL) << 48;
@@ -160,14 +248,30 @@
         return v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8;
     }
 
+    /**
+     * Read a 32 bit float IEEE standard index is increased by 4
+     *
+     * @return the float
+     */
     public float readFloat() {
         return java.lang.Float.intBitsToFloat(readInt());
     }
 
+    /**
+     * Read a 64 bit double index is increased by 8
+     *
+     * @return double
+     */
     public double readDouble() {
         return java.lang.Double.longBitsToDouble(readLong());
     }
 
+    /**
+     * Read a byte buffer bytes are encoded as 4 byte length followed by length bytes index is
+     * increased by 4 + number of bytes
+     *
+     * @return byte array
+     */
     public @NonNull byte[] readBuffer() {
         int count = readInt();
         byte[] b = Arrays.copyOfRange(mBuffer, mIndex, mIndex + count);
@@ -175,6 +279,13 @@
         return b;
     }
 
+    /**
+     * Read a byte buffer limited to max size. bytes are encoded as 4 byte length followed by length
+     * bytes index is increased by 4 + number of bytes Throw an exception if the read excedes the
+     * max size. This is the preferred form of read buffer.
+     *
+     * @return byte array
+     */
     public @NonNull byte[] readBuffer(int maxSize) {
         int count = readInt();
         if (count < 0 || count > maxSize) {
@@ -186,12 +297,23 @@
         return b;
     }
 
+    /**
+     * Read a string encoded in UTF8 The buffer is red with readBuffer and converted to a String
+     *
+     * @return unicode string
+     */
     @NonNull
     public String readUTF8() {
         byte[] stringBuffer = readBuffer();
         return new String(stringBuffer);
     }
 
+    /**
+     * Read a string encoded in UTF8 The buffer is red with readBuffer and converted to a String
+     * This is the preferred readUTF8 because it catches errors
+     *
+     * @return unicode string
+     */
     @NonNull
     public String readUTF8(int maxSize) {
         byte[] stringBuffer = readBuffer(maxSize);
@@ -202,18 +324,33 @@
     // Write values
     ///////////////////////////////////////////////////////////////////////////
 
+    /**
+     * Write a boolean value. (written as a byte 1=true)
+     *
+     * @param value value to write
+     */
     public void writeBoolean(boolean value) {
         resize(1);
         mBuffer[mIndex++] = (byte) (value ? 1 : 0);
         mSize++;
     }
 
+    /**
+     * Write a byte value
+     *
+     * @param value value to write
+     */
     public void writeByte(int value) {
         resize(1);
         mBuffer[mIndex++] = (byte) value;
         mSize++;
     }
 
+    /**
+     * Write a short value
+     *
+     * @param value value to write
+     */
     public void writeShort(int value) {
         int need = 2;
         resize(need);
@@ -222,6 +359,11 @@
         mSize += need;
     }
 
+    /**
+     * Write a int (4 byte) value
+     *
+     * @param value value to write
+     */
     public void writeInt(int value) {
         int need = 4;
         resize(need);
@@ -232,6 +374,11 @@
         mSize += need;
     }
 
+    /**
+     * Write a long (8 byte) value
+     *
+     * @param value value to write
+     */
     public void writeLong(long value) {
         int need = 8;
         resize(need);
@@ -246,14 +393,29 @@
         mSize += need;
     }
 
+    /**
+     * Write a 32 bit IEEE float value
+     *
+     * @param value value to write
+     */
     public void writeFloat(float value) {
         writeInt(Float.floatToRawIntBits(value));
     }
 
+    /**
+     * Write a 64 bit IEEE double value
+     *
+     * @param value value to write
+     */
     public void writeDouble(double value) {
         writeLong(Double.doubleToRawLongBits(value));
     }
 
+    /**
+     * Write a buffer The buffer length is first written followed by the bytes
+     *
+     * @param b array of bytes write
+     */
     public void writeBuffer(@NonNull byte[] b) {
         resize(b.length + 4);
         writeInt(b.length);
@@ -263,6 +425,11 @@
         mSize += b.length;
     }
 
+    /**
+     * Write a string is encoded as UTF8
+     *
+     * @param content the string to write
+     */
     public void writeUTF8(@NonNull String content) {
         byte[] buffer = content.getBytes();
         writeBuffer(buffer);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
index 9480076..27ba652 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
@@ -36,7 +36,7 @@
  * Operation to deal with bitmap data On getting an Image during a draw call the bitmap is
  * compressed and saved in playback the image is decompressed
  */
-public class BitmapData implements Operation, SerializableToString {
+public class BitmapData extends Operation implements SerializableToString {
     private static final int OP_CODE = Operations.DATA_BITMAP;
     private static final String CLASS_NAME = "BitmapData";
     int mImageId;
@@ -85,6 +85,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -119,6 +124,12 @@
         buffer.writeBuffer(bitmap);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int imageId = buffer.readInt();
         int width = buffer.readInt();
@@ -133,6 +144,11 @@
         operations.add(new BitmapData(imageId, width, height, bitmap));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Data Operations", OP_CODE, CLASS_NAME)
                 .description("Bitmap data")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java
index 310b194..5e5e565 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java
@@ -28,7 +28,7 @@
 import java.util.List;
 
 /** Add a click area to the document */
-public class ClickArea implements RemoteComposeOperation {
+public class ClickArea extends Operation implements RemoteComposeOperation {
     private static final int OP_CODE = Operations.CLICK_AREA;
     private static final String CLASS_NAME = "ClickArea";
     int mId;
@@ -118,6 +118,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -141,6 +146,12 @@
         buffer.writeInt(metadata);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int id = buffer.readInt();
         int contentDescription = buffer.readInt();
@@ -154,6 +165,11 @@
         operations.add(clickArea);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Canvas Operations", OP_CODE, CLASS_NAME)
                 .description("Define a region you can click on")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java
index db93829..2fe56d3 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java
@@ -69,6 +69,12 @@
         return "ClipPath " + mId + ";";
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int pack = buffer.readInt();
         int id = pack & 0xFFFFF;
@@ -82,6 +88,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -91,6 +102,11 @@
         buffer.writeInt(id);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Canvas Operations", OP_CODE, CLASS_NAME)
                 .description("Intersect the current clip with the path")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java
index df54fb1..defa656 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java
@@ -31,11 +31,22 @@
     public static final int OP_CODE = Operations.CLIP_RECT;
     public static final String CLASS_NAME = "ClipRect";
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         Maker m = ClipRect::new;
         read(m, buffer, operations);
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -50,6 +61,11 @@
         apply(buffer, v1, v2, v3, v4);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Expressions Operations", OP_CODE, CLASS_NAME)
                 .description("Intersect the current clip with rectangle")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java
index 34e93f5..d86576d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java
@@ -29,12 +29,22 @@
 import java.util.List;
 
 /** Operation that defines a simple Color based on ID Mainly for colors in theming. */
-public class ColorConstant implements Operation {
+public class ColorConstant extends Operation {
     private static final int OP_CODE = Operations.COLOR_CONSTANT;
     private static final String CLASS_NAME = "ColorConstant";
+
+    /** the id of the color */
     public int mColorId;
+
+    /** the color value (AARRGGBB) */
     public int mColor;
 
+    /**
+     * Creat a color constant
+     *
+     * @param colorId id of color
+     * @param color AARRGGBB value
+     */
     public ColorConstant(int colorId, int color) {
         this.mColorId = colorId;
         this.mColor = color;
@@ -56,6 +66,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -73,12 +88,23 @@
         buffer.writeInt(color);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int colorId = buffer.readInt();
         int color = buffer.readInt();
         operations.add(new ColorConstant(colorId, color));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Expressions Operations", OP_CODE, CLASS_NAME)
                 .description("Define a Color")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
index c947d11..66f128f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
@@ -34,7 +34,7 @@
  * Operation to Colors Color modes mMode = 0 two colors and a tween mMode = 1 color1 is a colorID.
  * mMode = 2 color2 is a colorID. mMode = 3 color1 & color2 are ids mMode = 4 H S V mode
  */
-public class ColorExpression implements Operation, VariableSupport {
+public class ColorExpression extends Operation implements VariableSupport {
     private static final int OP_CODE = Operations.COLOR_EXPRESSIONS;
     private static final String CLASS_NAME = "ColorExpression";
     public int mId;
@@ -204,6 +204,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -228,6 +233,12 @@
         buffer.writeFloat(tween);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int id = buffer.readInt();
         int mode = buffer.readInt();
@@ -238,6 +249,11 @@
         operations.add(new ColorExpression(id, mode, color1, color2, tween));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Expressions Operations", OP_CODE, CLASS_NAME)
                 .description("A Color defined by an expression")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java
index b0ccd187..19c219b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java
@@ -30,7 +30,7 @@
 
 import java.util.List;
 
-public class ComponentValue implements Operation, SerializableToString {
+public class ComponentValue extends Operation implements SerializableToString {
     public static final int OP_CODE = Operations.COMPONENT_VALUE;
     public static final String CLASS_NAME = "ComponentValue";
 
@@ -41,6 +41,11 @@
     private int mComponentID = -1;
     private int mValueId = -1;
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -78,6 +83,12 @@
         // Nothing
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int type = buffer.readInt();
         int componentId = buffer.readInt();
@@ -86,6 +97,11 @@
         operations.add(op);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Expressions Operations", OP_CODE, CLASS_NAME)
                 .description("Encode a component-related value (eg its width, height etc.)")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java
index bfaf139..ac6271c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java
@@ -32,7 +32,7 @@
 import java.util.Arrays;
 import java.util.List;
 
-public class DataListFloat implements VariableSupport, ArrayAccess, Operation {
+public class DataListFloat extends Operation implements VariableSupport, ArrayAccess {
     private static final int OP_CODE = Operations.FLOAT_LIST;
     private static final String CLASS_NAME = "IdListData";
     private final int mId;
@@ -79,6 +79,12 @@
         }
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int id = buffer.readInt();
         int len = buffer.readInt();
@@ -93,6 +99,11 @@
         operations.add(data);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Data Operations", OP_CODE, CLASS_NAME)
                 .description("a list of Floats")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java
index 9b286b9..47cbff3 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java
@@ -33,7 +33,7 @@
 import java.util.Arrays;
 import java.util.List;
 
-public class DataListIds implements VariableSupport, ArrayAccess, Operation {
+public class DataListIds extends Operation implements VariableSupport, ArrayAccess {
     private static final int OP_CODE = Operations.ID_LIST;
     private static final String CLASS_NAME = "IdListData";
     private final int mId;
@@ -71,6 +71,12 @@
         }
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int id = buffer.readInt();
         int len = buffer.readInt();
@@ -85,6 +91,11 @@
         operations.add(data);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Data Operations", OP_CODE, CLASS_NAME)
                 .description("a list of id's")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java
index 643afc8..e888074 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java
@@ -31,7 +31,7 @@
 import java.util.List;
 
 /** This is a map of strings to type & Id */
-public class DataMapIds implements Operation {
+public class DataMapIds extends Operation {
     private static final int OP_CODE = Operations.ID_MAP;
     private static final String CLASS_NAME = "DataMapIds";
     int mId;
@@ -105,6 +105,12 @@
         }
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int id = buffer.readInt();
         int len = buffer.readInt();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapLookup.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapLookup.java
index eae532c..9af2343 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapLookup.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapLookup.java
@@ -31,7 +31,7 @@
 import java.util.List;
 
 /** This can lookup in a map given a string writing the results to an id. */
-public class DataMapLookup implements Operation {
+public class DataMapLookup extends Operation {
     private static final int OP_CODE = Operations.DATA_MAP_LOOKUP;
     private static final String CLASS_NAME = "DataMapLookup";
     public int mId;
@@ -109,12 +109,17 @@
         operations.add(new DataMapLookup(id, mapId, stringId));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Expressions Operations", OP_CODE, CLASS_NAME)
-                .description("A float and its associated id")
+                .description("Look up a value in a data map")
                 .field(INT, "id", "id of float")
                 .field(INT, "dataMapId", "32-bit float value")
-                .field(INT, "value", "32-bit float value");
+                .field(INT, "stringId", "32-bit float value");
     }
 
     @Override
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java
index 629f786..3f95f02 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java
@@ -30,11 +30,22 @@
     public static final int OP_CODE = Operations.DRAW_ARC;
     private static final String CLASS_NAME = "DrawArc";
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         Maker m = DrawArc::new;
         read(m, buffer, operations);
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -79,6 +90,11 @@
         apply(buffer, v1, v2, v3, v4, v5, v6);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Canvas Operations", OP_CODE, CLASS_NAME)
                 .description(
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java
index 9c23c95..69f5cc5 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java
@@ -100,15 +100,21 @@
                 + ";";
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int id = buffer.readInt();
         float sLeft = buffer.readFloat();
         float srcTop = buffer.readFloat();
         float srcRight = buffer.readFloat();
         float srcBottom = buffer.readFloat();
-        int discriptionId = buffer.readInt();
+        int descriptionId = buffer.readInt();
 
-        DrawBitmap op = new DrawBitmap(id, sLeft, srcTop, srcRight, srcBottom, discriptionId);
+        DrawBitmap op = new DrawBitmap(id, sLeft, srcTop, srcRight, srcBottom, descriptionId);
         operations.add(op);
     }
 
@@ -117,6 +123,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -138,6 +149,11 @@
         buffer.writeInt(descriptionId);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Draw Operations", OP_CODE, CLASS_NAME)
                 .description("Draw a bitmap")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java
index da9fe24..66646d7 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java
@@ -111,6 +111,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -140,6 +145,12 @@
         buffer.writeInt(cdId);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int imageId = buffer.readInt();
         int sLeft = buffer.readInt();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java
index e9f81d5..1701486 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java
@@ -196,6 +196,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -232,6 +237,12 @@
         buffer.writeInt(cdId);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int imageId = buffer.readInt();
 
@@ -265,6 +276,11 @@
         operations.add(op);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Draw Operations", OP_CODE, CLASS_NAME)
                 .description("Draw a bitmap using integer coordinates")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java
index 11bd49a..e6aecdb 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java
@@ -30,11 +30,22 @@
     private static final int OP_CODE = Operations.DRAW_CIRCLE;
     private static final String CLASS_NAME = "DrawCircle";
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         Maker m = DrawCircle::new;
         read(m, buffer, operations);
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -44,6 +55,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Canvas Operations", OP_CODE, CLASS_NAME)
                 .description("Draw a Circle")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java
index 7310a9d..04f3264 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java
@@ -32,11 +32,22 @@
     private static final int OP_CODE = Operations.DRAW_LINE;
     private static final String CLASS_NAME = "DrawLine";
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         Maker m = DrawLine::new;
         read(m, buffer, operations);
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -46,6 +57,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Canvas Operations", OP_CODE, CLASS_NAME)
                 .description("Draw a line segment")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java
index aa5116e..0a50042 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java
@@ -30,11 +30,22 @@
     private static final int OP_CODE = Operations.DRAW_OVAL;
     private static final String CLASS_NAME = "DrawOval";
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         Maker m = DrawOval::new;
         read(m, buffer, operations);
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -44,6 +55,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Canvas Operations", OP_CODE, CLASS_NAME)
                 .description("Draw the specified oval")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java
index d35094b..41b8243 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java
@@ -50,6 +50,12 @@
         return "DrawPath " + "[" + mId + "]" + ", " + mStart + ", " + mEnd;
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int id = buffer.readInt();
         DrawPath op = new DrawPath(id);
@@ -61,6 +67,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.DRAW_PATH;
     }
@@ -70,6 +81,11 @@
         buffer.writeInt(id);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Draw Operations", OP_CODE, CLASS_NAME)
                 .description("Draw a bitmap using integer coordinates")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java
index db7633c..7e22550 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java
@@ -31,11 +31,22 @@
     private static final int OP_CODE = Operations.DRAW_RECT;
     private static final String CLASS_NAME = "DrawRect";
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         Maker m = DrawRect::new;
         read(m, buffer, operations);
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -45,6 +56,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Canvas Operations", OP_CODE, CLASS_NAME)
                 .description("Draw the specified rectangle")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java
index c306e2b..a41e46e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java
@@ -31,11 +31,22 @@
     private static final int OP_CODE = Operations.DRAW_ROUND_RECT;
     private static final String CLASS_NAME = "DrawRoundRect";
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         Maker m = DrawRoundRect::new;
         read(m, buffer, operations);
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -80,6 +91,11 @@
         apply(buffer, v1, v2, v3, v4, v5, v6);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Canvas Operations", OP_CODE, CLASS_NAME)
                 .description("Draw the specified round-rect")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java
index 3b60df7..7616df0 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java
@@ -30,11 +30,22 @@
     public static final int OP_CODE = Operations.DRAW_SECTOR;
     private static final String CLASS_NAME = "DrawSector";
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         Maker m = DrawSector::new;
         read(m, buffer, operations);
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -79,6 +90,11 @@
         apply(buffer, v1, v2, v3, v4, v5, v6);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Canvas Operations", OP_CODE, CLASS_NAME)
                 .description(
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java
index 9c587ab..2c5d790 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java
@@ -101,6 +101,12 @@
                 + floatToString(mY, mOutY);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int text = buffer.readInt();
         int start = buffer.readInt();
@@ -120,6 +126,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -158,6 +169,11 @@
         buffer.writeBoolean(rtl);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Draw Operations", id(), CLASS_NAME)
                 .description("Draw a run of text, all in a single direction")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java
index 8b70181..7de52b8 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java
@@ -111,6 +111,12 @@
         return Float.toString(v);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int textID = buffer.readInt();
         float x = buffer.readFloat();
@@ -129,6 +135,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -161,6 +172,11 @@
         buffer.writeInt(flags);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Draw Operations", OP_CODE, CLASS_NAME)
                 .description("Draw text centered about an anchor point")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
index e90122b..18d9fdf 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
@@ -83,6 +83,12 @@
                 + Utils.floatToString(mVOffset, mOutVOffset);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int textId = buffer.readInt();
         int pathId = buffer.readInt();
@@ -97,6 +103,11 @@
         return "DrawTextOnPath";
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.DRAW_TEXT_ON_PATH;
     }
@@ -110,6 +121,11 @@
         buffer.writeFloat(hOffset);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Draw Operations", OP_CODE, CLASS_NAME)
                 .description("Draw text along path object")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java
index 0aaaf42..b83e4c2 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java
@@ -92,6 +92,12 @@
                 + floatToString(mStop, mOutStop);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int path1Id = buffer.readInt();
         int path2Id = buffer.readInt();
@@ -107,6 +113,11 @@
         return "DrawTweenPath";
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.DRAW_TWEEN_PATH;
     }
@@ -126,6 +137,11 @@
         buffer.writeFloat(stop);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Draw Operations", OP_CODE, CLASS_NAME)
                 .description("Draw text along path object")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
index 17aaf3b..7dd435a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
@@ -29,7 +29,7 @@
 import java.util.List;
 
 /** Operation to deal with Text data */
-public class FloatConstant implements com.android.internal.widget.remotecompose.core.Operation {
+public class FloatConstant extends Operation {
     private static final int OP_CODE = Operations.DATA_FLOAT;
     private static final String CLASS_NAME = "FloatConstant";
     public int mTextId;
@@ -56,6 +56,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -73,6 +78,12 @@
         buffer.writeFloat(value);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int textId = buffer.readInt();
 
@@ -80,6 +91,11 @@
         operations.add(new FloatConstant(textId, value));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Expressions Operations", OP_CODE, CLASS_NAME)
                 .description("A float and its associated id")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
index eef9746..3d92e12 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
@@ -42,7 +42,7 @@
  * like injecting the width of the component int draw rect As well as supporting generalized
  * animation floats. The floats represent a RPN style calculator
  */
-public class FloatExpression implements Operation, VariableSupport {
+public class FloatExpression extends Operation implements VariableSupport {
     private static final int OP_CODE = Operations.ANIMATED_FLOAT;
     private static final String CLASS_NAME = "FloatExpression";
     public int mId;
@@ -146,16 +146,19 @@
         if (Float.isNaN(mLastChange)) {
             mLastChange = t;
         }
-        if (mFloatAnimation != null) {
+        if (mFloatAnimation != null && !Float.isNaN(mLastCalculatedValue)) {
             float f = mFloatAnimation.get(t - mLastChange);
             context.loadFloat(mId, f);
         } else if (mSpring != null) {
             float f = mSpring.get(t - mLastChange);
             context.loadFloat(mId, f);
         } else {
-            context.loadFloat(
-                    mId,
-                    mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length));
+            float v =
+                    mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length);
+            if (mFloatAnimation != null) {
+                mFloatAnimation.setTargetValue(v);
+            }
+            context.loadFloat(mId, v);
         }
     }
 
@@ -207,6 +210,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -243,12 +251,18 @@
         }
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int id = buffer.readInt();
         int len = buffer.readInt();
         int valueLen = len & 0xFFFF;
         if (valueLen > MAX_EXPRESSION_SIZE) {
-            throw new RuntimeException("Float expression to long");
+            throw new RuntimeException("Float expression too long");
         }
         int animLen = (len >> 16) & 0xFFFF;
         float[] values = new float[valueLen];
@@ -268,6 +282,11 @@
         operations.add(new FloatExpression(id, values, animation));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Expressions Operations", OP_CODE, CLASS_NAME)
                 .description("A Float expression")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java
index 009aa03..04e4346 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java
@@ -35,7 +35,7 @@
  * <p>It encodes the version of the document (following semantic versioning) as well as the
  * dimensions of the document in pixels.
  */
-public class Header implements RemoteComposeOperation {
+public class Header extends Operation implements RemoteComposeOperation {
     private static final int OP_CODE = Operations.HEADER;
     private static final String CLASS_NAME = "Header";
     public static final int MAJOR_VERSION = 0;
@@ -120,6 +120,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -136,6 +141,12 @@
         buffer.writeLong(capabilities);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int majorVersion = buffer.readInt();
         int minorVersion = buffer.readInt();
@@ -157,6 +168,11 @@
         operations.add(header);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Protocol Operations", OP_CODE, CLASS_NAME)
                 .description(
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java
index c49f74d..67274af 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java
@@ -38,7 +38,7 @@
  * like injecting the width of the component int draw rect As well as supporting generalized
  * animation floats. The floats represent a RPN style calculator
  */
-public class IntegerExpression implements Operation, VariableSupport {
+public class IntegerExpression extends Operation implements VariableSupport {
     private static final int OP_CODE = Operations.INTEGER_EXPRESSION;
     private static final String CLASS_NAME = "IntegerExpression";
     public int mId;
@@ -141,6 +141,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -163,6 +168,12 @@
         }
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int id = buffer.readInt();
         int mask = buffer.readInt();
@@ -178,6 +189,11 @@
         operations.add(new IntegerExpression(id, mask, values));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Data Operations", OP_CODE, CLASS_NAME)
                 .description("Expression that computes an integer")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
index 4e7ee4d..aed597a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
@@ -37,6 +37,12 @@
         apply(buffer);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         MatrixRestore op = new MatrixRestore();
         operations.add(op);
@@ -53,6 +59,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -61,6 +72,11 @@
         buffer.start(OP_CODE);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Canvas Operations", OP_CODE, CLASS_NAME)
                 .description("Restore the matrix and clip");
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java
index 438a2aa..fece143 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java
@@ -30,6 +30,12 @@
     public static final int OP_CODE = Operations.MATRIX_ROTATE;
     private static final String CLASS_NAME = "MatrixRotate";
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         Maker m =
                 new Maker() {
@@ -42,6 +48,11 @@
         read(m, buffer, operations);
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -51,6 +62,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Canvas Operations", OP_CODE, CLASS_NAME)
                 .description("apply rotation to matrix")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java
index 09f54a5..7eb7b3f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java
@@ -41,6 +41,12 @@
         return "MatrixSave;";
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         MatrixSave op = new MatrixSave();
         operations.add(op);
@@ -51,6 +57,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -59,6 +70,11 @@
         buffer.start(Operations.MATRIX_SAVE);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Canvas Operations", OP_CODE, CLASS_NAME)
                 .description("Save the matrix and clip to a stack");
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java
index 6304584..49bdd1b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java
@@ -30,11 +30,22 @@
     public static final int OP_CODE = Operations.MATRIX_SCALE;
     public static final String CLASS_NAME = "MatrixScale";
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         Maker m = MatrixScale::new;
         read(m, buffer, operations);
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -49,9 +60,14 @@
         apply(buffer, v1, v2, v3, v4);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Canvas Operations", OP_CODE, CLASS_NAME)
-                .description("Draw the specified Oval")
+                .description("Scale the following draw commands")
                 .field(DocumentedOperation.FLOAT, "scaleX", "The amount to scale in X")
                 .field(DocumentedOperation.FLOAT, "scaleY", "The amount to scale in Y")
                 .field(DocumentedOperation.FLOAT, "pivotX", "The x-coordinate for the pivot point")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java
index 675cf0d..54b6fd1 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java
@@ -31,11 +31,22 @@
     public static final int OP_CODE = Operations.MATRIX_SKEW;
     public static final String CLASS_NAME = "MatrixSkew";
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         Maker m = MatrixSkew::new;
         read(m, buffer, operations);
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -50,6 +61,11 @@
         apply(buffer, v1, v2);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Canvas Operations", OP_CODE, CLASS_NAME)
                 .description("Current matrix with the specified skew.")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java
index b0a7d35..b57d83b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java
@@ -30,11 +30,22 @@
     public static final int OP_CODE = Operations.MATRIX_TRANSLATE;
     public static final String CLASS_NAME = "MatrixTranslate";
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         Maker m = MatrixTranslate::new;
         read(m, buffer, operations);
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -49,6 +60,11 @@
         apply(buffer, v1, v2);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Canvas Operations", OP_CODE, "MatrixTranslate")
                 .description("Preconcat the current matrix with the specified translation")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
index 5ca91af..3c82f2b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
@@ -30,7 +30,7 @@
 import java.util.List;
 
 /** Operation to deal with Text data */
-public class NamedVariable implements Operation {
+public class NamedVariable extends Operation {
     private static final int OP_CODE = Operations.NAMED_VARIABLE;
     private static final String CLASS_NAME = "NamedVariable";
     public final int mVarId;
@@ -69,6 +69,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -89,6 +94,12 @@
         buffer.writeUTF8(text);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int varId = buffer.readInt();
         int varType = buffer.readInt();
@@ -96,6 +107,11 @@
         operations.add(new NamedVariable(varId, varType, text));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Data Operations", OP_CODE, CLASS_NAME)
                 .description("Add a string name for an ID")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
index b24df8a..3c0a842 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
@@ -66,6 +66,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -75,6 +80,12 @@
         paintBundle.writeBundle(buffer);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         PaintData data = new PaintData();
         data.mPaintData.readBundle(buffer);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java
new file mode 100644
index 0000000..2b00001
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java
@@ -0,0 +1,230 @@
+/*
+ * 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.internal.widget.remotecompose.core.operations;
+
+import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT_ARRAY;
+import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class PathAppend extends PaintOperation implements VariableSupport {
+    private static final int OP_CODE = Operations.PATH_ADD;
+    private static final String CLASS_NAME = "PathAppend";
+    int mInstanceId;
+    float[] mFloatPath;
+    float[] mOutputPath;
+
+    PathAppend(int instanceId, float[] floatPath) {
+        mInstanceId = instanceId;
+        mFloatPath = floatPath;
+        mOutputPath = Arrays.copyOf(mFloatPath, mFloatPath.length);
+    }
+
+    @Override
+    public void updateVariables(@NonNull RemoteContext context) {
+        for (int i = 0; i < mFloatPath.length; i++) {
+            float v = mFloatPath[i];
+            if (Utils.isVariable(v)) {
+                mOutputPath[i] = Float.isNaN(v) ? context.getFloat(Utils.idFromNan(v)) : v;
+            } else {
+                mOutputPath[i] = v;
+            }
+        }
+    }
+
+    @Override
+    public void registerListening(@NonNull RemoteContext context) {
+        for (float v : mFloatPath) {
+            if (Float.isNaN(v)) {
+                context.listensTo(Utils.idFromNan(v), this);
+            }
+        }
+    }
+
+    @Override
+    public void write(@NonNull WireBuffer buffer) {
+        apply(buffer, mInstanceId, mOutputPath);
+    }
+
+    @NonNull
+    @Override
+    public String deepToString(String indent) {
+        return PathData.pathString(mFloatPath);
+    }
+
+    @NonNull
+    @Override
+    public String toString() {
+        return "PathAppend[" + mInstanceId + "] += " + "\"" + pathString(mOutputPath) + "\"";
+    }
+
+    /**
+     * public float[] getFloatPath(PaintContext context) { float[] ret = mRetFloats; // Assume
+     * retFloats is declared elsewhere if (ret == null) { return mFloatPath; // Assume floatPath is
+     * declared elsewhere } float[] localRef = mRef; // Assume ref is of type Float[] if (localRef
+     * == null) { for (int i = 0; i < mFloatPath.length; i++) { ret[i] = mFloatPath[i]; } } else {
+     * for (int i = 0; i < mFloatPath.length; i++) { float lr = localRef[i]; if (Float.isNaN(lr)) {
+     * ret[i] = Utils.getActualValue(lr); } else { ret[i] = mFloatPath[i]; } } } return ret; }
+     */
+    public static final int MOVE = 10;
+
+    public static final int LINE = 11;
+    public static final int QUADRATIC = 12;
+    public static final int CONIC = 13;
+    public static final int CUBIC = 14;
+    public static final int CLOSE = 15;
+    public static final int DONE = 16;
+    public static final float MOVE_NAN = Utils.asNan(MOVE);
+    public static final float LINE_NAN = Utils.asNan(LINE);
+    public static final float QUADRATIC_NAN = Utils.asNan(QUADRATIC);
+    public static final float CONIC_NAN = Utils.asNan(CONIC);
+    public static final float CUBIC_NAN = Utils.asNan(CUBIC);
+    public static final float CLOSE_NAN = Utils.asNan(CLOSE);
+    public static final float DONE_NAN = Utils.asNan(DONE);
+
+    @NonNull
+    public static String name() {
+        return CLASS_NAME;
+    }
+
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
+    public static int id() {
+        return OP_CODE;
+    }
+
+    public static void apply(@NonNull WireBuffer buffer, int id, @NonNull float[] data) {
+        buffer.start(OP_CODE);
+        buffer.writeInt(id);
+        buffer.writeInt(data.length);
+        for (float datum : data) {
+            buffer.writeFloat(datum);
+        }
+    }
+
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
+    public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
+        int id = buffer.readInt();
+        int len = buffer.readInt();
+        float[] data = new float[len];
+        for (int i = 0; i < data.length; i++) {
+            data[i] = buffer.readFloat();
+        }
+        operations.add(new PathAppend(id, data));
+    }
+
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
+    public static void documentation(@NonNull DocumentationBuilder doc) {
+        doc.operation("Data Operations", OP_CODE, CLASS_NAME)
+                .description("Append to a Path")
+                .field(DocumentedOperation.INT, "id", "id string")
+                .field(INT, "length", "id string")
+                .field(FLOAT_ARRAY, "pathData", "length", "path encoded as floats");
+    }
+
+    @Override
+    public void paint(PaintContext context) {}
+
+    @Override
+    public void apply(@NonNull RemoteContext context) {
+        updateVariables(context);
+        float[] data = context.getPathData(mInstanceId);
+        float[] out = mOutputPath;
+        if (data != null) {
+            out = new float[data.length + mOutputPath.length];
+
+            for (int i = 0; i < data.length; i++) {
+                out[i] = data[i];
+            }
+            for (int i = 0; i < mOutputPath.length; i++) {
+                out[i + data.length] = mOutputPath[i];
+            }
+        } else {
+            System.out.println(">>>>>>>>>>> DATA IS NULL");
+        }
+        context.loadPathData(mInstanceId, out);
+    }
+
+    @NonNull
+    public static String pathString(@Nullable float[] path) {
+        if (path == null) {
+            return "null";
+        }
+        StringBuilder str = new StringBuilder();
+        for (int i = 0; i < path.length; i++) {
+            if (Float.isNaN(path[i])) {
+                int id = Utils.idFromNan(path[i]); // Assume idFromNan is defined elsewhere
+                if (id <= DONE) { // Assume DONE is a constant
+                    switch (id) {
+                        case MOVE:
+                            str.append("M");
+                            break;
+                        case LINE:
+                            str.append("L");
+                            break;
+                        case QUADRATIC:
+                            str.append("Q");
+                            break;
+                        case CONIC:
+                            str.append("R");
+                            break;
+                        case CUBIC:
+                            str.append("C");
+                            break;
+                        case CLOSE:
+                            str.append("Z");
+                            break;
+                        case DONE:
+                            str.append(".");
+                            break;
+                        default:
+                            str.append("[" + id + "]");
+                            break;
+                    }
+                } else {
+                    str.append("(" + id + ")");
+                }
+            }
+        }
+        return str.toString();
+    }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java
new file mode 100644
index 0000000..b62f36b
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java
@@ -0,0 +1,206 @@
+/*
+ * 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.internal.widget.remotecompose.core.operations;
+
+import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class PathCreate extends PaintOperation implements VariableSupport {
+    private static final int OP_CODE = Operations.PATH_CREATE;
+    private static final String CLASS_NAME = "PathCreate";
+    int mInstanceId;
+    float[] mFloatPath;
+    float[] mOutputPath;
+
+    PathCreate(int instanceId, float startX, float startY) {
+        mInstanceId = instanceId;
+        mFloatPath = new float[] {PathData.MOVE_NAN, startX, startY};
+        mOutputPath = Arrays.copyOf(mFloatPath, mFloatPath.length);
+    }
+
+    @Override
+    public void updateVariables(@NonNull RemoteContext context) {
+        for (int i = 0; i < mFloatPath.length; i++) {
+            float v = mFloatPath[i];
+            if (Utils.isVariable(v)) {
+                mOutputPath[i] = Float.isNaN(v) ? context.getFloat(Utils.idFromNan(v)) : v;
+            } else {
+                mOutputPath[i] = v;
+            }
+        }
+    }
+
+    @Override
+    public void registerListening(@NonNull RemoteContext context) {
+        for (float v : mFloatPath) {
+            if (Float.isNaN(v)) {
+                context.listensTo(Utils.idFromNan(v), this);
+            }
+        }
+    }
+
+    @Override
+    public void write(@NonNull WireBuffer buffer) {
+        apply(buffer, mInstanceId, mFloatPath[1], mFloatPath[2]);
+    }
+
+    @NonNull
+    @Override
+    public String deepToString(String indent) {
+        return pathString(mFloatPath);
+    }
+
+    @NonNull
+    @Override
+    public String toString() {
+        return "PathCreate[" + mInstanceId + "] = " + "\"" + deepToString(" ") + "\"";
+    }
+
+    public static final int MOVE = 10;
+    public static final int LINE = 11;
+    public static final int QUADRATIC = 12;
+    public static final int CONIC = 13;
+    public static final int CUBIC = 14;
+    public static final int CLOSE = 15;
+    public static final int DONE = 16;
+    public static final float MOVE_NAN = Utils.asNan(MOVE);
+    public static final float LINE_NAN = Utils.asNan(LINE);
+    public static final float QUADRATIC_NAN = Utils.asNan(QUADRATIC);
+    public static final float CONIC_NAN = Utils.asNan(CONIC);
+    public static final float CUBIC_NAN = Utils.asNan(CUBIC);
+    public static final float CLOSE_NAN = Utils.asNan(CLOSE);
+    public static final float DONE_NAN = Utils.asNan(DONE);
+
+    @NonNull
+    public static String name() {
+        return CLASS_NAME;
+    }
+
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
+    public static int id() {
+        return OP_CODE;
+    }
+
+    public static void apply(@NonNull WireBuffer buffer, int id, float startX, float startY) {
+        buffer.start(OP_CODE);
+        buffer.writeInt(id);
+        buffer.writeFloat(startX);
+        buffer.writeFloat(startY);
+    }
+
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
+    public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
+
+        int id = buffer.readInt();
+        float startX = buffer.readFloat();
+        float startY = buffer.readFloat();
+        operations.add(new PathCreate(id, startX, startY));
+    }
+
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
+    public static void documentation(@NonNull DocumentationBuilder doc) {
+        doc.operation("Data Operations", OP_CODE, CLASS_NAME)
+                .description("Encode a Path ")
+                .field(DocumentedOperation.INT, "id", "id of path")
+                .field(FLOAT, "startX", "initial start x")
+                .field(FLOAT, "startX", "initial start y");
+    }
+
+    @NonNull
+    public static String pathString(@Nullable float[] path) {
+        if (path == null) {
+            return "null";
+        }
+        StringBuilder str = new StringBuilder();
+        for (int i = 0; i < path.length; i++) {
+            if (i != 0) {
+                str.append(" ");
+            }
+            if (Float.isNaN(path[i])) {
+                int id = Utils.idFromNan(path[i]); // Assume idFromNan is defined elsewhere
+                if (id <= DONE) { // Assume DONE is a constant
+                    switch (id) {
+                        case MOVE:
+                            str.append("M");
+                            break;
+                        case LINE:
+                            str.append("L");
+                            break;
+                        case QUADRATIC:
+                            str.append("Q");
+                            break;
+                        case CONIC:
+                            str.append("R");
+                            break;
+                        case CUBIC:
+                            str.append("C");
+                            break;
+                        case CLOSE:
+                            str.append("Z");
+                            break;
+                        case DONE:
+                            str.append(".");
+                            break;
+                        default:
+                            str.append("[" + id + "]");
+                            break;
+                    }
+                } else {
+                    str.append("(" + id + ")");
+                }
+            } else {
+                str.append(path[i]);
+            }
+        }
+        return str.toString();
+    }
+
+    @Override
+    public void paint(PaintContext context) {}
+
+    @Override
+    public void apply(@NonNull RemoteContext context) {
+        context.loadPathData(mInstanceId, mOutputPath);
+    }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
index 509f362..4ec5436 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
@@ -32,7 +32,7 @@
 import java.util.Arrays;
 import java.util.List;
 
-public class PathData implements Operation, VariableSupport {
+public class PathData extends Operation implements VariableSupport {
     private static final int OP_CODE = Operations.DATA_PATH;
     private static final String CLASS_NAME = "PathData";
     int mInstanceId;
@@ -112,6 +112,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -125,6 +130,12 @@
         }
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int imageId = buffer.readInt();
         int len = buffer.readInt();
@@ -135,6 +146,11 @@
         operations.add(new PathData(imageId, data));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Data Operations", OP_CODE, CLASS_NAME)
                 .description("Encode a Path ")
@@ -143,6 +159,12 @@
                 .field(FLOAT_ARRAY, "pathData", "length", "path encoded as floats");
     }
 
+    /**
+     * Render a path as a string
+     *
+     * @param path path as a array of floats
+     * @return string describing the path
+     */
     @NonNull
     public static String pathString(@Nullable float[] path) {
         if (path == null) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java
new file mode 100644
index 0000000..a6fa680
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
+import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString;
+
+import android.annotation.NonNull;
+
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+
+import java.util.List;
+
+/** Operation to deal with Path data */
+public class PathTween extends PaintOperation implements VariableSupport {
+    private static final int OP_CODE = Operations.PATH_TWEEN;
+    private static final String CLASS_NAME = "PathTween";
+    public int mOutId;
+    public int mPathId1;
+    public int mPathId2;
+    public float mTween;
+    public float mTweenOut;
+
+    public PathTween(int outId, int pathId1, int pathId2, float tween) {
+        this.mOutId = outId;
+        this.mPathId1 = pathId1;
+        this.mPathId2 = pathId2;
+        this.mTween = tween;
+        this.mTweenOut = mTween;
+    }
+
+    @Override
+    public void updateVariables(@NonNull RemoteContext context) {
+        mTweenOut = Float.isNaN(mTween) ? context.getFloat(Utils.idFromNan(mTween)) : mTween;
+    }
+
+    @Override
+    public void registerListening(@NonNull RemoteContext context) {
+        if (Float.isNaN(mTween)) {
+            context.listensTo(Utils.idFromNan(mTween), this);
+        }
+    }
+
+    @Override
+    public void write(@NonNull WireBuffer buffer) {
+        apply(buffer, mOutId, mPathId1, mPathId2, mTween);
+    }
+
+    @NonNull
+    @Override
+    public String toString() {
+        return "PathTween["
+                + mOutId
+                + "] = ["
+                + mPathId1
+                + " ] + [ "
+                + mPathId2
+                + "], "
+                + floatToString(mTween, mTweenOut);
+    }
+
+    @NonNull
+    public static String name() {
+        return CLASS_NAME;
+    }
+
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
+    public static int id() {
+        return OP_CODE;
+    }
+
+    /**
+     * Writes out the operation to the buffer
+     *
+     * @param buffer buffer to write to
+     * @param outId id of the path
+     * @param pathId1 source path 1
+     * @param pathId2 source path 2
+     * @param tween interpolate between two paths
+     */
+    public static void apply(
+            @NonNull WireBuffer buffer, int outId, int pathId1, int pathId2, float tween) {
+        buffer.start(OP_CODE);
+        buffer.writeInt(outId);
+        buffer.writeInt(pathId1);
+        buffer.writeInt(pathId2);
+        buffer.writeFloat(tween);
+    }
+
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
+    public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
+        int outId1 = buffer.readInt();
+        int pathId1 = buffer.readInt();
+        int pathId2 = buffer.readInt();
+        float tween = buffer.readFloat();
+
+        operations.add(new PathTween(outId1, pathId1, pathId2, tween));
+    }
+
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
+    public static void documentation(@NonNull DocumentationBuilder doc) {
+        doc.operation("Data Operations", OP_CODE, CLASS_NAME)
+                .description("Merge two string into one")
+                .field(DocumentedOperation.INT, "pathId", "id of the path")
+                .field(INT, "srcPathId1", "id of the path")
+                .field(INT, "srcPathId1", "x Shift of the path");
+    }
+
+    @NonNull
+    @Override
+    public String deepToString(String indent) {
+        return indent + toString();
+    }
+
+    @Override
+    public void paint(PaintContext context) {
+        context.tweenPath(mOutId, mPathId1, mPathId2, mTweenOut);
+    }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java
index 8494126..aaa7176 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java
@@ -33,7 +33,7 @@
  * <p>It encodes the version of the document (following semantic versioning) as well as the
  * dimensions of the document in pixels.
  */
-public class RootContentBehavior implements RemoteComposeOperation {
+public class RootContentBehavior extends Operation implements RemoteComposeOperation {
     private static final int OP_CODE = Operations.ROOT_CONTENT_BEHAVIOR;
     private static final String CLASS_NAME = "RootContentBehavior";
     int mScroll = NONE;
@@ -205,6 +205,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -218,6 +223,12 @@
         buffer.writeInt(mode);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int scroll = buffer.readInt();
         int alignment = buffer.readInt();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
index 109945f..e92daa3 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
@@ -28,7 +28,7 @@
 import java.util.List;
 
 /** Describe a content description for the document */
-public class RootContentDescription implements RemoteComposeOperation {
+public class RootContentDescription extends Operation implements RemoteComposeOperation {
     private static final int OP_CODE = Operations.ROOT_CONTENT_DESCRIPTION;
     private static final String CLASS_NAME = "RootContentDescription";
     int mContentDescription;
@@ -69,6 +69,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -78,12 +83,23 @@
         buffer.writeInt(contentDescription);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int contentDescription = buffer.readInt();
         RootContentDescription header = new RootContentDescription(contentDescription);
         operations.add(header);
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Protocol Operations", OP_CODE, CLASS_NAME)
                 .description("Content description of root")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
index e967ff4..e2502fe 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
@@ -41,7 +41,7 @@
  * Operation to deal with bitmap data On getting an Image during a draw call the bitmap is
  * compressed and saved in playback the image is decompressed
  */
-public class ShaderData implements Operation, VariableSupport {
+public class ShaderData extends Operation implements VariableSupport {
     private static final int OP_CODE = Operations.DATA_SHADER;
     private static final String CLASS_NAME = "ShaderData";
     int mShaderTextId; // the actual text of a shader
@@ -203,6 +203,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -266,6 +271,12 @@
         }
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int shaderID = buffer.readInt();
         int shaderTextId = buffer.readInt();
@@ -318,6 +329,11 @@
         operations.add(new ShaderData(shaderID, shaderTextId, floatMap, intMap, bitmapMap));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Data Operations", OP_CODE, CLASS_NAME)
                 .description("Shader")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
index ade008e..3f679bf 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
@@ -31,7 +31,7 @@
 import java.util.List;
 
 /** Operation to deal with Text data */
-public class TextData implements Operation, SerializableToString {
+public class TextData extends Operation implements SerializableToString {
     private static final int OP_CODE = Operations.DATA_TEXT;
     private static final String CLASS_NAME = "TextData";
     public final int mTextId;
@@ -59,6 +59,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -69,6 +74,12 @@
         buffer.writeUTF8(text);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int textId = buffer.readInt();
 
@@ -76,6 +87,11 @@
         operations.add(new TextData(textId, text));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Data Operations", OP_CODE, CLASS_NAME)
                 .description("Encode a string ")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
index 865ee81f..4d01e0c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
@@ -36,7 +36,7 @@
  * [command][textID][before,after][flags] before and after define number of digits before and after
  * the decimal point
  */
-public class TextFromFloat implements Operation, VariableSupport {
+public class TextFromFloat extends Operation implements VariableSupport {
     private static final int OP_CODE = Operations.TEXT_FROM_FLOAT;
     private static final String CLASS_NAME = "TextFromFloat";
     public int mTextId;
@@ -127,6 +127,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -155,6 +160,12 @@
         buffer.writeInt(flags);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int textId = buffer.readInt();
         float value = buffer.readFloat();
@@ -166,6 +177,11 @@
         operations.add(new TextFromFloat(textId, value, pre, post, flags));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Expressions Operations", OP_CODE, CLASS_NAME)
                 .description("Draw text along path object")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLength.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLength.java
index 6ff687b..37ea567 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLength.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLength.java
@@ -28,7 +28,7 @@
 import java.util.List;
 
 /** Operation to measure the length of the text */
-public class TextLength implements Operation {
+public class TextLength extends Operation {
     private static final int OP_CODE = Operations.TEXT_LENGTH;
     private static final String CLASS_NAME = "TextLength";
     public int mLengthId;
@@ -54,6 +54,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -71,12 +76,23 @@
         buffer.writeInt(textId);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int lengthId = buffer.readInt();
         int textId = buffer.readInt();
         operations.add(new TextLength(lengthId, textId));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Expressions Operations", OP_CODE, CLASS_NAME)
                 .description("get the length of the text and store in float table")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java
index cc812a8..3ec6f01 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java
@@ -34,7 +34,7 @@
  * [command][textID][before,after][flags] before and after define number of digits before and after
  * the decimal point
  */
-public class TextLookup implements Operation, VariableSupport {
+public class TextLookup extends Operation implements VariableSupport {
     private static final int OP_CODE = Operations.TEXT_LOOKUP;
     private static final String CLASS_NAME = "TextFromFloat";
     public int mTextId;
@@ -84,6 +84,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -103,6 +108,12 @@
         buffer.writeFloat(index);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int textId = buffer.readInt();
         int dataSetId = buffer.readInt();
@@ -110,6 +121,11 @@
         operations.add(new TextLookup(textId, dataSetId, index));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Expressions Operations", OP_CODE, CLASS_NAME)
                 .description("Look an array and turn into a text object")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java
index 74be698..9c0ee53 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java
@@ -30,7 +30,7 @@
 import java.util.List;
 
 /** Operation convert int index of a list to text */
-public class TextLookupInt implements Operation, VariableSupport {
+public class TextLookupInt extends Operation implements VariableSupport {
     private static final int OP_CODE = Operations.TEXT_LOOKUP_INT;
     private static final String CLASS_NAME = "TextFromINT";
     public int mTextId;
@@ -77,6 +77,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -96,6 +101,12 @@
         buffer.writeInt(indexId);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int textId = buffer.readInt();
         int dataSetId = buffer.readInt();
@@ -103,6 +114,11 @@
         operations.add(new TextLookupInt(textId, dataSetId, indexId));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Expressions Operations", OP_CODE, CLASS_NAME)
                 .description("Look up an array and turn into a text object")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMeasure.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMeasure.java
index 6d48f67..d51b389 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMeasure.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMeasure.java
@@ -70,6 +70,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -89,6 +94,12 @@
         buffer.writeInt(type);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int id = buffer.readInt();
         int textId = buffer.readInt();
@@ -96,9 +107,14 @@
         operations.add(new TextMeasure(id, textId, type));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Expressions Operations", OP_CODE, CLASS_NAME)
-                .description("A float and its associated id")
+                .description("Measure text")
                 .field(INT, "id", "id of float result of the measure")
                 .field(INT, "textId", "id of text")
                 .field(INT, "type", "type: measure 0=width,1=height");
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
index ecd5baa..5b0c38f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
@@ -29,7 +29,7 @@
 import java.util.List;
 
 /** Operation to deal with Text data */
-public class TextMerge implements Operation {
+public class TextMerge extends Operation {
     private static final int OP_CODE = Operations.TEXT_MERGE;
     private static final String CLASS_NAME = "TextMerge";
     public int mTextId;
@@ -58,6 +58,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -77,6 +82,12 @@
         buffer.writeInt(srcId2);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int textId = buffer.readInt();
         int srcId1 = buffer.readInt();
@@ -85,6 +96,11 @@
         operations.add(new TextMerge(textId, srcId1, srcId2));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Data Operations", OP_CODE, CLASS_NAME)
                 .description("Merge two string into one")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java
index d265070..e329c38d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java
@@ -33,7 +33,7 @@
  * "tag" the subsequent operations to a given theme. On playback, we can then filter operations
  * depending on the chosen theme.
  */
-public class Theme implements RemoteComposeOperation {
+public class Theme extends Operation implements RemoteComposeOperation {
     private static final int OP_CODE = Operations.THEME;
     private static final String CLASS_NAME = "Theme";
     int mTheme;
@@ -77,6 +77,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -86,11 +91,22 @@
         buffer.writeInt(theme);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int theme = buffer.readInt();
         operations.add(new Theme(theme));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Protocol Operations", OP_CODE, CLASS_NAME)
                 .description("Set a theme")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java
index 1bb7b2a..e2e20bc 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java
@@ -42,12 +42,12 @@
  * touch behaviours. Including animating to Notched, positions. and tweaking the dynamics of the
  * animation.
  */
-public class TouchExpression implements Operation, VariableSupport, TouchListener {
+public class TouchExpression extends Operation implements VariableSupport, TouchListener {
     private static final int OP_CODE = Operations.TOUCH_EXPRESSION;
     private static final String CLASS_NAME = "TouchExpression";
     private float mDefValue;
     private float mOutDefValue;
-    public int mId;
+    private int mId;
     public float[] mSrcExp;
     int mMode = 1; // 0 = delta, 1 = absolute
     float mMax = 1;
@@ -56,11 +56,14 @@
     float mOutMin = 1;
     float mValue = 0;
     boolean mUnmodified = true;
-    public float[] mPreCalcValue;
+    private float[] mPreCalcValue;
     private float mLastChange = Float.NaN;
     private float mLastCalculatedValue = Float.NaN;
     AnimatedFloatExpression mExp = new AnimatedFloatExpression();
+
+    /** The maximum number of floats in the expression */
     public static final int MAX_EXPRESSION_SIZE = 32;
+
     private VelocityEasing mEasyTouch = new VelocityEasing();
     private boolean mEasingToStop = false;
     private float mTouchUpTime = 0;
@@ -495,6 +498,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -505,6 +513,14 @@
      * @param buffer The buffer to write to
      * @param id the id of the resulting float
      * @param value the float expression array
+     * @param min the minimum allowed value
+     * @param max the maximum allowed value
+     * @param velocityId the velocity id
+     * @param touchEffects the type touch effect
+     * @param exp the expression the maps touch drags to movement
+     * @param touchMode the touch mode e.g. notch modes
+     * @param touchSpec the spec of the touch modes
+     * @param easingSpec the spec of when the object comes to an easing
      */
     public static void apply(
             WireBuffer buffer,
@@ -549,7 +565,13 @@
         }
     }
 
-    public static void read(WireBuffer buffer, List<Operation> operations) {
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
+    public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int id = buffer.readInt();
         float startValue = buffer.readFloat();
         float min = buffer.readFloat();
@@ -594,6 +616,11 @@
                         easingData));
     }
 
+    /**
+     * Populate the documentation with a description of this operation
+     *
+     * @param doc to append the description to.
+     */
     public static void documentation(DocumentationBuilder doc) {
         doc.operation("Expressions Operations", OP_CODE, CLASS_NAME)
                 .description("A Float expression")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java
index baca3e0..de43b90 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java
@@ -19,34 +19,60 @@
 
 /** Utilities to be used across all core operations */
 public class Utils {
+    /**
+     * Convert an integer id into a float
+     *
+     * @param v the integer id to convert
+     * @return the id as an float
+     */
     public static float asNan(int v) {
         return Float.intBitsToFloat(v | -0x800000);
     }
 
+    /**
+     * convert a float into an integer id
+     *
+     * @param value the float id to convert
+     * @return the id as an integer
+     */
     public static int idFromNan(float value) {
         int b = Float.floatToRawIntBits(value);
         return b & 0x3FFFFF;
     }
 
+    /**
+     * convert a long into an ID
+     *
+     * @param v the long to convert
+     * @return the id still as a long
+     */
     public static long idFromLong(long v) {
         return v - 0x100000000L;
     }
 
+    /**
+     * convert a float id and turn it into a string
+     *
+     * @param value float to convert
+     * @return string form of an id
+     */
     @NonNull
     public static String idStringFromNan(float value) {
         int b = Float.floatToRawIntBits(value) & 0x3FFFFF;
         return idString(b);
     }
 
+    /**
+     * print an id as a string
+     *
+     * @param b the id
+     * @return the id as a string
+     */
     @NonNull
     public static String idString(int b) {
         return (b > 0xFFFFF) ? "A_" + (b & 0xFFFFF) : "" + b;
     }
 
-    public static float getActualValue(float lr) {
-        return 0;
-    }
-
     /**
      * trim a string to n characters if needing to trim end in "..."
      *
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ActionOperation.java
index 7f1d101..0f84059 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ActionOperation.java
@@ -18,12 +18,11 @@
 import android.annotation.NonNull;
 
 import com.android.internal.widget.remotecompose.core.CoreDocument;
-import com.android.internal.widget.remotecompose.core.Operation;
 import com.android.internal.widget.remotecompose.core.RemoteContext;
 import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
 
 /** Operations representing actions on the document */
-public interface ActionOperation extends Operation {
+public interface ActionOperation {
     void serializeToString(int indent, @NonNull StringSerializer serializer);
 
     void runAction(
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java
index aa8f7580..121b180 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java
@@ -46,6 +46,11 @@
         return "CanvasContent";
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.LAYOUT_CANVAS_CONTENT;
     }
@@ -61,6 +66,12 @@
         buffer.writeInt(componentId);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int componentId = buffer.readInt();
         operations.add(new CanvasContent(componentId, 0, 0, 0, 0, null, -1));
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java
index f44e20d..34c4249 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java
@@ -182,6 +182,12 @@
         buffer.start(OP_CODE);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         operations.add(new ClickModifierOperation());
     }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java
index fbfc796..faa259f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java
@@ -26,7 +26,6 @@
 import com.android.internal.widget.remotecompose.core.SerializableToString;
 import com.android.internal.widget.remotecompose.core.VariableSupport;
 import com.android.internal.widget.remotecompose.core.WireBuffer;
-import com.android.internal.widget.remotecompose.core.operations.BitmapData;
 import com.android.internal.widget.remotecompose.core.operations.ComponentValue;
 import com.android.internal.widget.remotecompose.core.operations.TextData;
 import com.android.internal.widget.remotecompose.core.operations.layout.animation.AnimateMeasure;
@@ -468,11 +467,6 @@
         value[0] += mX;
         value[1] += mY;
         if (mParent != null) {
-            if (mParent instanceof LayoutComponent) {
-                LayoutComponent parent = (LayoutComponent) mParent;
-                value[0] += parent.getMarginLeft() + parent.getPaddingLeft();
-                value[1] += parent.getMarginTop() + parent.getPaddingTop();
-            }
             mParent.getLocationInWindow(value);
         }
     }
@@ -658,12 +652,7 @@
             debugBox(this, context);
         }
         for (Operation op : mList) {
-            if (op instanceof BitmapData) {
-                ((BitmapData) op).apply(context.getContext());
-            }
-            if (op instanceof PaintOperation) {
-                ((PaintOperation) op).paint(context);
-            }
+            op.apply(context.getContext());
         }
         context.restore();
         context.getContext().mLastComponent = prev;
@@ -701,7 +690,7 @@
         if (applyAnimationAsNeeded(context)) {
             return;
         }
-        if (mVisibility == Visibility.GONE) {
+        if (mVisibility == Visibility.GONE || mVisibility == Visibility.INVISIBLE) {
             return;
         }
         paintingComponent(context);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java
index 476b73c..396644c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java
@@ -25,7 +25,7 @@
 
 import java.util.List;
 
-public class ComponentEnd implements Operation {
+public class ComponentEnd extends Operation {
 
     @Override
     public void write(@NonNull WireBuffer buffer) {
@@ -54,6 +54,11 @@
         return "ComponentEnd";
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.COMPONENT_END;
     }
@@ -66,6 +71,12 @@
         return 1 + 4 + 4 + 4;
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         operations.add(new ComponentEnd());
     }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java
index def9f78..a85ae27 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java
@@ -28,7 +28,7 @@
 
 import java.util.List;
 
-public class ComponentStart implements ComponentStartOperation {
+public class ComponentStart extends Operation implements ComponentStartOperation {
 
     int mType = DEFAULT;
     float mX;
@@ -162,6 +162,11 @@
         return "ComponentStart";
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.COMPONENT_START;
     }
@@ -179,6 +184,12 @@
         return 1 + 4 + 4 + 4;
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int type = buffer.readInt();
         int componentId = buffer.readInt();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStartOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStartOperation.java
index abf2356a..a257d46 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStartOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStartOperation.java
@@ -15,6 +15,4 @@
  */
 package com.android.internal.widget.remotecompose.core.operations.layout;
 
-import com.android.internal.widget.remotecompose.core.Operation;
-
-public interface ComponentStartOperation extends Operation {}
+public interface ComponentStartOperation {}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java
index 0041582..7b0e4a2 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java
@@ -19,8 +19,10 @@
 import android.annotation.Nullable;
 
 import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.OperationInterface;
 import com.android.internal.widget.remotecompose.core.PaintContext;
 import com.android.internal.widget.remotecompose.core.operations.BitmapData;
+import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
 import com.android.internal.widget.remotecompose.core.operations.MatrixRestore;
 import com.android.internal.widget.remotecompose.core.operations.MatrixSave;
 import com.android.internal.widget.remotecompose.core.operations.MatrixTranslate;
@@ -47,12 +49,6 @@
     @Nullable protected ZIndexModifierOperation mZIndexModifier = null;
     @Nullable protected GraphicsLayerModifierOperation mGraphicsLayerModifier = null;
 
-    // Margins
-    protected float mMarginLeft = 0f;
-    protected float mMarginRight = 0f;
-    protected float mMarginTop = 0f;
-    protected float mMarginBottom = 0f;
-
     protected float mPaddingLeft = 0f;
     protected float mPaddingRight = 0f;
     protected float mPaddingTop = 0f;
@@ -76,22 +72,6 @@
         super(parent, componentId, animationId, x, y, width, height);
     }
 
-    public float getMarginLeft() {
-        return mMarginLeft;
-    }
-
-    public float getMarginRight() {
-        return mMarginRight;
-    }
-
-    public float getMarginTop() {
-        return mMarginTop;
-    }
-
-    public float getMarginBottom() {
-        return mMarginBottom;
-    }
-
     public float getPaddingLeft() {
         return mPaddingLeft;
     }
@@ -133,8 +113,7 @@
 
     public void inflate() {
         ArrayList<TextData> data = new ArrayList<>();
-        ArrayList<TouchExpression> touchExpressions = new ArrayList<>();
-        ArrayList<PaintData> paintData = new ArrayList<>();
+        ArrayList<Operation> supportedOperations = new ArrayList<>();
 
         for (Operation op : mList) {
             if (op instanceof LayoutComponentContent) {
@@ -179,10 +158,10 @@
                 mComponentModifiers.add((ModifierOperation) op);
             } else if (op instanceof TextData) {
                 data.add((TextData) op);
-            } else if (op instanceof TouchExpression) {
-                touchExpressions.add((TouchExpression) op);
-            } else if (op instanceof PaintData) {
-                paintData.add((PaintData) op);
+            } else if (op instanceof TouchExpression
+                    || (op instanceof PaintData)
+                    || (op instanceof FloatExpression)) {
+                supportedOperations.add(op);
             } else {
                 // nothing
             }
@@ -190,8 +169,7 @@
 
         mList.clear();
         mList.addAll(data);
-        mList.addAll(touchExpressions);
-        mList.addAll(paintData);
+        mList.addAll(supportedOperations);
         mList.add(mComponentModifiers);
         for (Component c : mChildrenComponents) {
             c.mParent = this;
@@ -203,10 +181,6 @@
 
         mX = 0f;
         mY = 0f;
-        mMarginLeft = 0f;
-        mMarginTop = 0f;
-        mMarginRight = 0f;
-        mMarginBottom = 0f;
         mPaddingLeft = 0f;
         mPaddingTop = 0f;
         mPaddingRight = 0f;
@@ -214,7 +188,7 @@
 
         boolean applyHorizontalMargin = true;
         boolean applyVerticalMargin = true;
-        for (Operation op : mComponentModifiers.getList()) {
+        for (OperationInterface op : mComponentModifiers.getList()) {
             if (op instanceof PaddingModifierOperation) {
                 // We are accumulating padding modifiers to compute the margin
                 // until we hit a dimension; the computed padding for the
@@ -223,31 +197,17 @@
                 float right = ((PaddingModifierOperation) op).getRight();
                 float top = ((PaddingModifierOperation) op).getTop();
                 float bottom = ((PaddingModifierOperation) op).getBottom();
-                if (applyHorizontalMargin) {
-                    mMarginLeft += left;
-                    mMarginRight += right;
-                }
-                if (applyVerticalMargin) {
-                    mMarginTop += top;
-                    mMarginBottom += bottom;
-                }
                 mPaddingLeft += left;
                 mPaddingTop += top;
                 mPaddingRight += right;
                 mPaddingBottom += bottom;
-            }
-            if (op instanceof WidthModifierOperation && mWidthModifier == null) {
+            } else if (op instanceof WidthModifierOperation && mWidthModifier == null) {
                 mWidthModifier = (WidthModifierOperation) op;
-                applyHorizontalMargin = false;
-            }
-            if (op instanceof HeightModifierOperation && mHeightModifier == null) {
+            } else if (op instanceof HeightModifierOperation && mHeightModifier == null) {
                 mHeightModifier = (HeightModifierOperation) op;
-                applyVerticalMargin = false;
-            }
-            if (op instanceof ZIndexModifierOperation) {
+            } else if (op instanceof ZIndexModifierOperation) {
                 mZIndexModifier = (ZIndexModifierOperation) op;
-            }
-            if (op instanceof GraphicsLayerModifierOperation) {
+            } else if (op instanceof GraphicsLayerModifierOperation) {
                 mGraphicsLayerModifier = (GraphicsLayerModifierOperation) op;
             }
         }
@@ -339,7 +299,7 @@
         float s = 0f;
         float e = 0f;
         float w = 0f;
-        for (Operation c : mComponentModifiers.getList()) {
+        for (OperationInterface c : mComponentModifiers.getList()) {
             if (c instanceof WidthModifierOperation) {
                 WidthModifierOperation o = (WidthModifierOperation) c;
                 if (o.getType() == DimensionModifierOperation.Type.EXACT
@@ -366,7 +326,7 @@
     public float computeModifierDefinedPaddingWidth(@NonNull float[] padding) {
         float s = 0f;
         float e = 0f;
-        for (Operation c : mComponentModifiers.getList()) {
+        for (OperationInterface c : mComponentModifiers.getList()) {
             if (c instanceof PaddingModifierOperation) {
                 PaddingModifierOperation pop = (PaddingModifierOperation) c;
                 s += pop.getLeft();
@@ -383,7 +343,7 @@
         float t = 0f;
         float b = 0f;
         float h = 0f;
-        for (Operation c : mComponentModifiers.getList()) {
+        for (OperationInterface c : mComponentModifiers.getList()) {
             if (c instanceof HeightModifierOperation) {
                 HeightModifierOperation o = (HeightModifierOperation) c;
                 if (o.getType() == DimensionModifierOperation.Type.EXACT
@@ -410,7 +370,7 @@
     public float computeModifierDefinedPaddingHeight(@NonNull float[] padding) {
         float t = 0f;
         float b = 0f;
-        for (Operation c : mComponentModifiers.getList()) {
+        for (OperationInterface c : mComponentModifiers.getList()) {
             if (c instanceof PaddingModifierOperation) {
                 PaddingModifierOperation pop = (PaddingModifierOperation) c;
                 t += pop.getTop();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java
index 7eea885..20e4688 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java
@@ -46,6 +46,11 @@
         return "LayoutContent";
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.LAYOUT_CONTENT;
     }
@@ -61,6 +66,12 @@
         buffer.writeInt(componentId);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int componentId = buffer.readInt();
         operations.add(new LayoutComponentContent(componentId, 0, 0, 0, 0, null, -1));
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java
index 71de285..d88f711 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java
@@ -25,7 +25,7 @@
 
 import java.util.List;
 
-public class LoopEnd implements Operation {
+public class LoopEnd extends Operation {
 
     @Override
     public void write(@NonNull WireBuffer buffer) {
@@ -54,6 +54,11 @@
         return "LoopEnd";
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.LOOP_END;
     }
@@ -62,6 +67,12 @@
         buffer.start(id());
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         operations.add(new LoopEnd());
     }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java
index d88382d..83a2f0e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java
@@ -21,31 +21,57 @@
 import com.android.internal.widget.remotecompose.core.Operations;
 import com.android.internal.widget.remotecompose.core.PaintContext;
 import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
 import com.android.internal.widget.remotecompose.core.VariableSupport;
 import com.android.internal.widget.remotecompose.core.WireBuffer;
 import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+import com.android.internal.widget.remotecompose.core.operations.Utils;
 
 import java.util.ArrayList;
 import java.util.List;
 
 /** Represents a loop of operations */
-public class LoopOperation extends PaintOperation {
+public class LoopOperation extends PaintOperation implements VariableSupport {
     private static final int OP_CODE = Operations.LOOP_START;
 
     @NonNull public ArrayList<Operation> mList = new ArrayList<>();
 
     int mIndexVariableId;
-    float mUntil = 12;
-    float mFrom = 0;
-    float mStep = 1;
+    float mUntil;
+    float mFrom;
+    float mStep;
+    float mUntilOut;
+    float mFromOut;
+    float mStepOut;
 
     public LoopOperation(int count, int indexId) {
         mUntil = count;
         mIndexVariableId = indexId;
     }
 
-    public LoopOperation(float count, float from, float step, int indexId) {
-        mUntil = count;
+    @Override
+    public void registerListening(RemoteContext context) {
+        if (Float.isNaN(mUntil)) {
+            context.listensTo(Utils.idFromNan(mUntil), this);
+        }
+        if (Float.isNaN(mFrom)) {
+            context.listensTo(Utils.idFromNan(mFrom), this);
+        }
+        if (Float.isNaN(mStep)) {
+            context.listensTo(Utils.idFromNan(mStep), this);
+        }
+    }
+
+    @Override
+    public void updateVariables(RemoteContext context) {
+        mUntilOut = Float.isNaN(mUntil) ? context.getFloat(Utils.idFromNan(mUntil)) : mUntil;
+        mFromOut = Float.isNaN(mFrom) ? context.getFloat(Utils.idFromNan(mFrom)) : mFrom;
+        mStepOut = Float.isNaN(mStep) ? context.getFloat(Utils.idFromNan(mStep)) : mStep;
+    }
+
+    public LoopOperation(int indexId, float from, float step, float until) {
+        mUntil = until;
         mFrom = from;
         mStep = step;
         mIndexVariableId = indexId;
@@ -58,13 +84,19 @@
 
     @Override
     public void write(@NonNull WireBuffer buffer) {
-        apply(buffer, mUntil, mFrom, mStep, mIndexVariableId);
+        apply(buffer, mIndexVariableId, mFrom, mStep, mUntil);
     }
 
     @NonNull
     @Override
     public String toString() {
-        return "LoopOperation";
+        StringBuilder builder = new StringBuilder("LoopOperation\n");
+        for (Operation operation : mList) {
+            builder.append("  ");
+            builder.append(operation);
+            builder.append("\n");
+        }
+        return builder.toString();
     }
 
     @NonNull
@@ -76,13 +108,13 @@
     @Override
     public void paint(@NonNull PaintContext context) {
         if (mIndexVariableId == 0) {
-            for (float i = mFrom; i < mUntil; i += mStep) {
+            for (float i = mFromOut; i < mUntilOut; i += mStepOut) {
                 for (Operation op : mList) {
                     op.apply(context.getContext());
                 }
             }
         } else {
-            for (float i = mFrom; i < mUntil; i += mStep) {
+            for (float i = mFromOut; i < mUntilOut; i += mStepOut) {
                 context.getContext().loadFloat(mIndexVariableId, i);
                 for (Operation op : mList) {
                     if (op instanceof VariableSupport) {
@@ -100,24 +132,34 @@
     }
 
     public static void apply(
-            @NonNull WireBuffer buffer, float count, float from, float step, int indexId) {
+            @NonNull WireBuffer buffer, int indexId, float from, float step, float until) {
         buffer.start(OP_CODE);
-        buffer.writeFloat(count);
+        buffer.writeInt(indexId);
         buffer.writeFloat(from);
         buffer.writeFloat(step);
-        buffer.writeInt(indexId);
+        buffer.writeFloat(until);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
-        float count = buffer.readFloat();
+        int indexId = buffer.readInt();
         float from = buffer.readFloat();
         float step = buffer.readFloat();
-        int indexId = buffer.readInt();
-        operations.add(new LoopOperation(count, from, step, indexId));
+        float until = buffer.readFloat();
+        operations.add(new LoopOperation(indexId, from, step, until));
     }
 
     public static void documentation(@NonNull DocumentationBuilder doc) {
         doc.operation("Operations", OP_CODE, name())
-                .description("Loop. This operation execute" + " a list of action in a loop");
+                .description("Loop. This operation execute" + " a list of action in a loop")
+                .field(DocumentedOperation.INT, "id", "if not 0 write value")
+                .field(DocumentedOperation.FLOAT, "from", "values starts at")
+                .field(DocumentedOperation.FLOAT, "step", "value step")
+                .field(DocumentedOperation.FLOAT, "until", "stops less than or equal");
     }
 }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java
index ca79003..99b7e68 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java
@@ -25,7 +25,7 @@
 
 import java.util.List;
 
-public class OperationsListEnd implements Operation {
+public class OperationsListEnd extends Operation {
 
     @Override
     public void write(@NonNull WireBuffer buffer) {
@@ -54,6 +54,11 @@
         return "ListEnd";
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.OPERATIONS_LIST_END;
     }
@@ -62,6 +67,12 @@
         buffer.start(id());
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         operations.add(new OperationsListEnd());
     }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java
index 85c7153..fd16287 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java
@@ -197,6 +197,11 @@
         return "RootLayout";
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.LAYOUT_ROOT;
     }
@@ -206,6 +211,12 @@
         buffer.writeInt(componentId);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int componentId = buffer.readInt();
         operations.add(new RootLayoutComponent(componentId, 0, 0, 0, 0, null, -1));
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java
index 0316f96..3185bb5 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java
@@ -84,6 +84,12 @@
         buffer.start(OP_CODE);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(WireBuffer buffer, List<Operation> operations) {
         operations.add(new TouchCancelModifierOperation());
     }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java
index 6fb7059..b230b09 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java
@@ -29,7 +29,7 @@
 import java.util.List;
 
 /** Basic component animation spec */
-public class AnimationSpec implements Operation {
+public class AnimationSpec extends Operation {
     int mAnimationId = -1;
     int mMotionDuration = 300;
     int mMotionEasingType = GeneralEasing.CUBIC_STANDARD;
@@ -142,6 +142,11 @@
         return "AnimationSpec";
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.ANIMATION_SPEC;
     }
@@ -193,6 +198,12 @@
         buffer.writeInt(animationToInt(exitAnimation));
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int animationId = buffer.readInt();
         int motionDuration = buffer.readInt();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java
index 47a9421..01cd7cc 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java
@@ -108,6 +108,8 @@
             @NonNull PaintContext context,
             float maxWidth,
             float maxHeight,
+            boolean horizontalWrap,
+            boolean verticalWrap,
             @NonNull MeasurePass measure,
             @NonNull Size size) {
         for (Component c : mChildrenComponents) {
@@ -175,6 +177,11 @@
         return "BoxLayout";
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.LAYOUT_BOX;
     }
@@ -192,6 +199,12 @@
         buffer.writeInt(verticalPositioning);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int componentId = buffer.readInt();
         int animationId = buffer.readInt();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java
index 476b1a66..665db26 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java
@@ -77,6 +77,11 @@
         return "CanvasLayout";
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.LAYOUT_CANVAS;
     }
@@ -87,6 +92,12 @@
         buffer.writeInt(animationId);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int componentId = buffer.readInt();
         int animationId = buffer.readInt();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java
index 68e18c6..5b9ee0f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java
@@ -125,17 +125,21 @@
             @NonNull PaintContext context,
             float maxWidth,
             float maxHeight,
+            boolean horizontalWrap,
+            boolean verticalWrap,
             @NonNull MeasurePass measure,
             @NonNull Size size) {
         DebugLog.s(() -> "COMPUTE WRAP SIZE in " + this + " (" + mComponentId + ")");
         int visibleChildrens = 0;
+        float currentMaxHeight = maxHeight;
         for (Component c : mChildrenComponents) {
-            c.measure(context, 0f, maxWidth, 0f, maxHeight, measure);
+            c.measure(context, 0f, maxWidth, 0f, currentMaxHeight, measure);
             ComponentMeasure m = measure.get(c);
             if (m.getVisibility() != Visibility.GONE) {
                 size.setWidth(Math.max(size.getWidth(), m.getW()));
                 size.setHeight(size.getHeight() + m.getH());
                 visibleChildrens++;
+                currentMaxHeight -= m.getH();
             }
         }
         if (!mChildrenComponents.isEmpty()) {
@@ -342,6 +346,11 @@
         return "ColumnLayout";
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.LAYOUT_COLUMN;
     }
@@ -361,6 +370,12 @@
         buffer.writeFloat(spacedBy);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int componentId = buffer.readInt();
         int animationId = buffer.readInt();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java
index 3b5aaf3..6a15b7f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java
@@ -53,6 +53,8 @@
             @NonNull PaintContext context,
             float maxWidth,
             float maxHeight,
+            boolean horizontalWrap,
+            boolean verticalWrap,
             @NonNull MeasurePass measure,
             @NonNull Size size) {
         // nothing here
@@ -129,42 +131,67 @@
             float maxHeight,
             @NonNull MeasurePass measure) {
         boolean hasWrap = true;
-        float measuredWidth =
-                Math.min(maxWidth, computeModifierDefinedWidth() - mMarginLeft - mMarginRight);
-        float measuredHeight =
-                Math.min(maxHeight, computeModifierDefinedHeight() - mMarginTop - mMarginBottom);
-        float insetMaxWidth = maxWidth - mMarginLeft - mMarginRight;
-        float insetMaxHeight = maxHeight - mMarginTop - mMarginBottom;
+
+        float measuredWidth = Math.min(maxWidth, computeModifierDefinedWidth());
+        float measuredHeight = Math.min(maxHeight, computeModifierDefinedHeight());
+        float insetMaxWidth = maxWidth - mPaddingLeft - mPaddingRight;
+        float insetMaxHeight = maxHeight - mPaddingTop - mPaddingBottom;
+
         if (mWidthModifier.isIntrinsicMin()) {
             maxWidth = intrinsicWidth();
         }
         if (mHeightModifier.isIntrinsicMin()) {
             maxHeight = intrinsicHeight();
         }
-        if (mWidthModifier.isWrap() || mHeightModifier.isWrap()) { // TODO: potential npe -- bbade@
+
+        boolean hasHorizontalWrap = mWidthModifier.isWrap();
+        boolean hasVerticalWrap = mHeightModifier.isWrap();
+        if (hasHorizontalWrap || hasVerticalWrap) { // TODO: potential npe -- bbade@
             mCachedWrapSize.setWidth(0f);
             mCachedWrapSize.setHeight(0f);
-            computeWrapSize(context, maxWidth, maxHeight, measure, mCachedWrapSize);
+            float wrapMaxWidth = insetMaxWidth;
+            float wrapMaxHeight = insetMaxHeight;
+            if (hasHorizontalWrap) {
+                wrapMaxWidth = insetMaxWidth - mPaddingLeft - mPaddingRight;
+            }
+            if (hasVerticalWrap) {
+                wrapMaxHeight = insetMaxHeight - mPaddingTop - mPaddingBottom;
+            }
+            computeWrapSize(
+                    context,
+                    wrapMaxWidth,
+                    wrapMaxHeight,
+                    mWidthModifier.isWrap(),
+                    mHeightModifier.isWrap(),
+                    measure,
+                    mCachedWrapSize);
             measuredWidth = mCachedWrapSize.getWidth();
+            if (hasHorizontalWrap) {
+                measuredWidth += mPaddingLeft + mPaddingRight;
+            }
             measuredHeight = mCachedWrapSize.getHeight();
+            if (hasVerticalWrap) {
+                measuredHeight += mPaddingTop + mPaddingBottom;
+            }
         } else {
             hasWrap = false;
         }
+
         if (isInHorizontalFill()) {
-            measuredWidth = insetMaxWidth;
+            measuredWidth = maxWidth;
         } else if (mWidthModifier.hasWeight()) {
             measuredWidth = Math.max(measuredWidth, computeModifierDefinedWidth());
         } else {
             measuredWidth = Math.max(measuredWidth, minWidth);
-            measuredWidth = Math.min(measuredWidth, insetMaxWidth);
+            measuredWidth = Math.min(measuredWidth, maxWidth);
         }
         if (isInVerticalFill()) { // todo: potential npe -- bbade@
-            measuredHeight = insetMaxHeight;
+            measuredHeight = maxHeight;
         } else if (mHeightModifier.hasWeight()) {
             measuredHeight = Math.max(measuredHeight, computeModifierDefinedHeight());
         } else {
             measuredHeight = Math.max(measuredHeight, minHeight);
-            measuredHeight = Math.min(measuredHeight, insetMaxHeight);
+            measuredHeight = Math.min(measuredHeight, maxHeight);
         }
         if (minWidth == maxWidth) {
             measuredWidth = maxWidth;
@@ -172,20 +199,27 @@
         if (minHeight == maxHeight) {
             measuredHeight = maxHeight;
         }
-        measuredWidth = Math.min(measuredWidth, insetMaxWidth);
-        measuredHeight = Math.min(measuredHeight, insetMaxHeight);
+
         if (!hasWrap) {
             if (hasHorizontalScroll()) {
                 mCachedWrapSize.setWidth(0f);
                 mCachedWrapSize.setHeight(0f);
-                computeWrapSize(context, Float.MAX_VALUE, maxHeight, measure, mCachedWrapSize);
+                computeWrapSize(
+                        context,
+                        Float.MAX_VALUE,
+                        maxHeight,
+                        false,
+                        false,
+                        measure,
+                        mCachedWrapSize);
                 float w = mCachedWrapSize.getWidth();
                 computeSize(context, 0f, w, 0, measuredHeight, measure);
                 mComponentModifiers.setHorizontalScrollDimension(measuredWidth, w);
             } else if (hasVerticalScroll()) {
                 mCachedWrapSize.setWidth(0f);
                 mCachedWrapSize.setHeight(0f);
-                computeWrapSize(context, maxWidth, Float.MAX_VALUE, measure, mCachedWrapSize);
+                computeWrapSize(
+                        context, maxWidth, Float.MAX_VALUE, false, false, measure, mCachedWrapSize);
                 float h = mCachedWrapSize.getHeight();
                 computeSize(context, 0f, measuredWidth, 0, h, measure);
                 mComponentModifiers.setVerticalScrollDimension(measuredHeight, h);
@@ -202,9 +236,6 @@
             cm.setH(measuredHeight);
         }
 
-        measuredWidth += mMarginLeft + mMarginRight;
-        measuredHeight += mMarginTop + mMarginBottom;
-
         ComponentMeasure m = measure.get(this);
         m.setW(measuredWidth);
         m.setH(measuredHeight);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java
index 0ce634f..0ec820b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java
@@ -123,21 +123,25 @@
             @NonNull PaintContext context,
             float maxWidth,
             float maxHeight,
+            boolean horizontalWrap,
+            boolean verticalWrap,
             @NonNull MeasurePass measure,
             @NonNull Size size) {
         DebugLog.s(() -> "COMPUTE WRAP SIZE in " + this + " (" + mComponentId + ")");
-        //        int visibleChildrens = 0;
+        int visibleChildrens = 0;
+        float currentMaxWidth = maxWidth;
         for (Component c : mChildrenComponents) {
-            c.measure(context, 0f, maxWidth, 0f, maxHeight, measure);
+            c.measure(context, 0f, currentMaxWidth, 0f, maxHeight, measure);
             ComponentMeasure m = measure.get(c);
             if (m.getVisibility() != Visibility.GONE) {
                 size.setWidth(size.getWidth() + m.getW());
                 size.setHeight(Math.max(size.getHeight(), m.getH()));
-                //                visibleChildrens++;
+                visibleChildrens++;
+                currentMaxWidth -= m.getW();
             }
         }
         if (!mChildrenComponents.isEmpty()) {
-            size.setWidth(size.getWidth() + (mSpacedBy * (mChildrenComponents.size() - 1)));
+            size.setWidth(size.getWidth() + (mSpacedBy * (visibleChildrens - 1)));
         }
         DebugLog.e();
     }
@@ -345,6 +349,11 @@
         return "RowLayout";
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.LAYOUT_ROW;
     }
@@ -364,6 +373,12 @@
         buffer.writeFloat(spacedBy);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int componentId = buffer.readInt();
         int animationId = buffer.readInt();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java
index 73a104b..61a3ec9 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java
@@ -159,10 +159,13 @@
             @NonNull PaintContext context,
             float maxWidth,
             float maxHeight,
+            boolean horizontalWrap,
+            boolean verticalWrap,
             @NonNull MeasurePass measure,
             @NonNull Size size) {
         LayoutManager layout = getLayout(currentLayoutIndex);
-        layout.computeWrapSize(context, maxWidth, maxHeight, measure, size);
+        layout.computeWrapSize(
+                context, maxWidth, maxHeight, horizontalWrap, verticalWrap, measure, size);
     }
 
     @Override
@@ -442,11 +445,7 @@
                     int id = c.getPaintId();
                     for (int i = 0; i < idIndex; i++) {
                         if (cacheListElementsId[i] == id) {
-                            context.translate(
-                                    previousLayout.getMarginLeft(), previousLayout.getMarginTop());
                             c.paint(context);
-                            context.translate(
-                                    -currentLayout.getMarginLeft(), -currentLayout.getMarginTop());
                             break;
                         }
                     }
@@ -472,16 +471,10 @@
                     // and fade in the new one
                     Component previousComponent = stateComponents[previousLayoutIndex];
                     if (previousComponent != null && component != previousComponent) {
-                        context.translate(
-                                currentLayout.getMarginLeft(), currentLayout.getMarginTop());
                         previousComponent.paint(context);
-                        context.translate(
-                                -currentLayout.getMarginLeft(), -currentLayout.getMarginTop());
                     }
                 }
-                context.translate(currentLayout.getMarginLeft(), currentLayout.getMarginTop());
                 component.paint(context);
-                context.translate(-currentLayout.getMarginLeft(), -currentLayout.getMarginTop());
             } else if (op instanceof PaintOperation) {
                 ((PaintOperation) op).paint(context);
             }
@@ -563,6 +556,12 @@
         buffer.writeInt(indexId);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int componentId = buffer.readInt();
         int animationId = buffer.readInt();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java
index a527e5a..8e7f538 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java
@@ -52,8 +52,8 @@
     private int mType = -1;
     private float mTextX;
     private float mTextY;
-    private float mTextW;
-    private float mTextH;
+    private float mTextW = -1;
+    private float mTextH = -1;
 
     @Nullable private String mCachedString = "";
 
@@ -66,7 +66,11 @@
 
     @Override
     public void updateVariables(@NonNull RemoteContext context) {
-        mCachedString = context.getText(mTextId);
+        String cachedString = context.getText(mTextId);
+        if (cachedString != null && cachedString.equalsIgnoreCase(mCachedString)) {
+            return;
+        }
+        mCachedString = cachedString;
         if (mType == -1) {
             if (mFontFamilyId != -1) {
                 String fontFamily = context.getText(mFontFamilyId);
@@ -86,8 +90,9 @@
                 mType = 0;
             }
         }
-        mNeedsMeasure = true;
-        needsRepaint();
+        mTextW = -1;
+        mTextH = -1;
+        invalidateMeasure();
     }
 
     public TextLayout(
@@ -168,7 +173,14 @@
             return;
         }
         int length = mCachedString.length();
-        context.drawTextRun(mTextId, 0, length, 0, 0, mTextX, mTextY, false);
+        if (mTextW > mWidth) {
+            context.save();
+            context.translate(getScrollX(), getScrollY());
+            context.drawTextRun(mTextId, 0, length, 0, 0, mTextX, mTextY, false);
+            context.restore();
+        } else {
+            context.drawTextRun(mTextId, 0, length, 0, 0, mTextX, mTextY, false);
+        }
         if (DEBUG) {
             mPaint.setStyle(PaintBundle.STYLE_FILL_AND_STROKE);
             mPaint.setColor(1f, 1F, 1F, 1F);
@@ -246,6 +258,8 @@
             @NonNull PaintContext context,
             float maxWidth,
             float maxHeight,
+            boolean horizontalWrap,
+            boolean verticalWrap,
             @NonNull MeasurePass measure,
             @NonNull Size size) {
         context.savePaint();
@@ -262,9 +276,9 @@
         context.restorePaint();
         float w = bounds[2] - bounds[0];
         float h = bounds[3] - bounds[1];
-        size.setWidth(w);
+        size.setWidth(Math.min(maxWidth, w));
         mTextX = -bounds[0];
-        size.setHeight(h);
+        size.setHeight(Math.min(maxHeight, h));
         mTextY = -bounds[1];
         mTextW = w;
         mTextH = h;
@@ -285,6 +299,11 @@
         return "TextLayout";
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.LAYOUT_TEXT;
     }
@@ -312,6 +331,12 @@
         buffer.writeInt(textAlign);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int componentId = buffer.readInt();
         int animationId = buffer.readInt();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java
index 71d2ba6..5df16c5 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java
@@ -114,6 +114,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -142,6 +147,12 @@
         buffer.writeInt(shapeType);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         float x = buffer.readFloat();
         float y = buffer.readFloat();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java
index 0707cd6..bfadd2f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java
@@ -160,6 +160,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -192,6 +197,12 @@
         buffer.writeInt(shapeType);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         float x = buffer.readFloat();
         float y = buffer.readFloat();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java
index e05b027..d0af872 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java
@@ -60,6 +60,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -68,6 +73,12 @@
         buffer.start(OP_CODE);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         operations.add(new ClipRectModifierOperation());
     }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java
index 471db0b..1e6ccfc 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java
@@ -34,7 +34,7 @@
 import java.util.List;
 
 /** Allows setting visibility on a component */
-public class ComponentVisibilityOperation
+public class ComponentVisibilityOperation extends Operation
         implements ModifierOperation, VariableSupport, DecoratorComponent {
     private static final int OP_CODE = Operations.MODIFIER_VISIBILITY;
 
@@ -79,6 +79,12 @@
         buffer.writeInt(valueId);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int valueId = buffer.readInt();
         operations.add(new ComponentVisibilityOperation(valueId));
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DimensionModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DimensionModifierOperation.java
index b9324f0..b11deae 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DimensionModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DimensionModifierOperation.java
@@ -17,13 +17,15 @@
 
 import android.annotation.NonNull;
 
+import com.android.internal.widget.remotecompose.core.Operation;
 import com.android.internal.widget.remotecompose.core.RemoteContext;
 import com.android.internal.widget.remotecompose.core.VariableSupport;
 import com.android.internal.widget.remotecompose.core.operations.Utils;
 import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
 
 /** Base class for dimension modifiers */
-public abstract class DimensionModifierOperation implements ModifierOperation, VariableSupport {
+public abstract class DimensionModifierOperation extends Operation
+        implements ModifierOperation, VariableSupport {
 
     public enum Type {
         EXACT,
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java
index 571e554..4252309 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java
@@ -206,6 +206,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java
index 7bb4a75..692b526 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java
@@ -37,6 +37,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -47,6 +52,12 @@
         buffer.writeFloat(value);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         Type type = Type.fromInt(buffer.readInt());
         float value = buffer.readFloat();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java
index d239bc8..333e281 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java
@@ -32,7 +32,7 @@
 import java.util.List;
 
 /** Capture a host action information. This can be triggered on eg. a click. */
-public class HostActionOperation implements ActionOperation {
+public class HostActionOperation extends Operation implements ActionOperation {
     private static final int OP_CODE = Operations.HOST_ACTION;
 
     int mActionId = -1;
@@ -88,6 +88,12 @@
         buffer.writeInt(actionId);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int actionId = buffer.readInt();
         operations.add(new HostActionOperation(actionId));
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java
index 3268e5e..f9a4270 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java
@@ -32,7 +32,7 @@
 import java.util.List;
 
 /** Capture a host action information. This can be triggered on eg. a click. */
-public class HostNamedActionOperation implements ActionOperation {
+public class HostNamedActionOperation extends Operation implements ActionOperation {
     private static final int OP_CODE = Operations.HOST_NAMED_ACTION;
 
     public static final int FLOAT_TYPE = 0;
@@ -112,6 +112,12 @@
         buffer.writeInt(valueId);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int textId = buffer.readInt();
         int type = buffer.readInt();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ModifierOperation.java
index 8f08f14..f8926fe 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ModifierOperation.java
@@ -17,10 +17,10 @@
 
 import android.annotation.NonNull;
 
-import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.OperationInterface;
 import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
 
 /** Represents a modifier */
-public interface ModifierOperation extends Operation {
+public interface ModifierOperation extends OperationInterface {
     void serializeToString(int indent, @NonNull StringSerializer serializer);
 }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java
index 8c07059..69c4e9a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java
@@ -94,6 +94,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java
index 2b6621e..545df64 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java
@@ -32,7 +32,7 @@
  * Represents a padding modifier. Padding modifiers can be chained and will impact following
  * modifiers.
  */
-public class PaddingModifierOperation implements ModifierOperation {
+public class PaddingModifierOperation extends Operation implements ModifierOperation {
     private static final int OP_CODE = Operations.MODIFIER_PADDING;
     public static final String CLASS_NAME = "PaddingModifierOperation";
     float mLeft;
@@ -118,6 +118,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.MODIFIER_PADDING;
     }
@@ -131,6 +136,12 @@
         buffer.writeFloat(bottom);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         float left = buffer.readFloat();
         float top = buffer.readFloat();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java
index 3fefc58..681501d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java
@@ -37,11 +37,22 @@
     public static final int OP_CODE = Operations.MODIFIER_ROUNDED_CLIP_RECT;
     public static final String CLASS_NAME = "RoundedClipRectModifierOperation";
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         Maker m = RoundedClipRectModifierOperation::new;
         read(m, buffer, operations);
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java
index 8dcfed9..0b66320 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java
@@ -134,6 +134,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java
index a97fcff..b96d3cc 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java
@@ -33,7 +33,7 @@
 import java.util.List;
 
 /** Apply a value change on an float variable. */
-public class ValueFloatChangeActionOperation implements ActionOperation {
+public class ValueFloatChangeActionOperation extends Operation implements ActionOperation {
     private static final int OP_CODE = Operations.VALUE_FLOAT_CHANGE_ACTION;
 
     int mTargetValueId = -1;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java
index 41586b4..d81b7ff 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java
@@ -32,7 +32,8 @@
 import java.util.List;
 
 /** Apply a value change on an integer variable. */
-public class ValueFloatExpressionChangeActionOperation implements ActionOperation {
+public class ValueFloatExpressionChangeActionOperation extends Operation
+        implements ActionOperation {
     private static final int OP_CODE = Operations.VALUE_FLOAT_EXPRESSION_CHANGE_ACTION;
 
     int mTargetValueId = -1;
@@ -88,6 +89,12 @@
         buffer.writeInt(value);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int valueId = buffer.readInt();
         int value = buffer.readInt();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java
index c2cd2ab..fb13b42 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java
@@ -32,7 +32,7 @@
 import java.util.List;
 
 /** Apply a value change on an integer variable. */
-public class ValueIntegerChangeActionOperation implements ActionOperation {
+public class ValueIntegerChangeActionOperation extends Operation implements ActionOperation {
     private static final int OP_CODE = Operations.VALUE_INTEGER_CHANGE_ACTION;
 
     int mTargetValueId = -1;
@@ -87,6 +87,12 @@
         buffer.writeInt(value);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int valueId = buffer.readInt();
         int value = buffer.readInt();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java
index 43fbb85..0fe88ad 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java
@@ -32,7 +32,8 @@
 import java.util.List;
 
 /** Apply a value change on an integer variable. */
-public class ValueIntegerExpressionChangeActionOperation implements ActionOperation {
+public class ValueIntegerExpressionChangeActionOperation extends Operation
+        implements ActionOperation {
     private static final int OP_CODE = Operations.VALUE_INTEGER_EXPRESSION_CHANGE_ACTION;
 
     long mTargetValueId = -1;
@@ -88,6 +89,12 @@
         buffer.writeLong(value);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         long valueId = buffer.readLong();
         long value = buffer.readLong();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java
index 1107889..a8d3b87 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java
@@ -32,7 +32,7 @@
 import java.util.List;
 
 /** Apply a value change on a string variable. */
-public class ValueStringChangeActionOperation implements ActionOperation {
+public class ValueStringChangeActionOperation extends Operation implements ActionOperation {
     private static final int OP_CODE = Operations.VALUE_STRING_CHANGE_ACTION;
 
     int mTargetValueId = -1;
@@ -91,6 +91,12 @@
         buffer.writeInt(value);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int valueId = buffer.readInt();
         int value = buffer.readInt();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java
index 3c757a8..f6d743f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java
@@ -37,6 +37,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
@@ -47,6 +52,12 @@
         buffer.writeFloat(value);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         Type type = Type.fromInt(buffer.readInt());
         float value = buffer.readFloat();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java
index 82c8f34..96ed2cd 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java
@@ -83,6 +83,11 @@
         return CLASS_NAME;
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return OP_CODE;
     }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
index 07cf762..9543469 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
@@ -498,6 +498,11 @@
         return ret;
     }
 
+    /**
+     * Write a bundle of paint changes to the buffer
+     *
+     * @param buffer bundle to write
+     */
     public void writeBundle(@NonNull WireBuffer buffer) {
         buffer.writeInt(mPos);
         for (int index = 0; index < mPos; index++) {
@@ -505,6 +510,11 @@
         }
     }
 
+    /**
+     * This will read the paint bundle off the wire buffer
+     *
+     * @param buffer the buffer to read
+     */
     public void readBundle(@NonNull WireBuffer buffer) {
         int len = buffer.readInt();
         if (len <= 0 || len > 1024) {
@@ -587,6 +597,9 @@
     public static final int RADIAL_GRADIENT = 1;
     public static final int SWEEP_GRADIENT = 2;
 
+    private int mLastShaderSet = -1;
+    private boolean mColorFilterSet = false;
+
     /**
      * sets a shader that draws a linear gradient along a line.
      *
@@ -722,12 +735,14 @@
         mArray[mPos] = COLOR_FILTER_ID | (mode << 16);
         mPos++;
         mArray[mPos++] = color;
+        mColorFilterSet = true;
     }
 
     /** This sets the color filter to null */
     public void clearColorFilter() {
         mArray[mPos] = CLEAR_COLOR_FILTER;
         mPos++;
+        mColorFilterSet = false;
     }
 
     /**
@@ -843,6 +858,7 @@
      * @param shaderId
      */
     public void setShader(int shaderId) {
+        mLastShaderSet = shaderId;
         mArray[mPos] = SHADER;
         mPos++;
         mArray[mPos] = shaderId;
@@ -909,11 +925,23 @@
         mPos++;
     }
 
+    /**
+     * clear a series of paint parameters. Currently not used
+     *
+     * @param mask bit pattern of the attributes to clear
+     */
     public void clear(long mask) { // unused for now
     }
 
+    /** Reset the content of the paint bundle so that it can be reused */
     public void reset() {
         mPos = 0;
+        if (mColorFilterSet) {
+            clearColorFilter();
+        }
+        if (mLastShaderSet != -1 && mLastShaderSet != 0) {
+            setShader(0);
+        }
     }
 
     public static @NonNull String blendModeString(int mode) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java
index e5633c7..a568747 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java
@@ -18,7 +18,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 
-import com.android.internal.widget.remotecompose.core.operations.Utils;
 import com.android.internal.widget.remotecompose.core.operations.utilities.easing.MonotonicSpline;
 
 /** high performance floating point expression evaluator used in animation */
@@ -141,7 +140,7 @@
         for (int i = 0; i < mStack.length; i++) {
             float v = mStack[i];
             if (Float.isNaN(v)) {
-                sp = mOps[fromNaN(v) - OFFSET].eval(sp);
+                sp = opEval(sp, fromNaN(v));
             } else {
                 mStack[++sp] = v;
             }
@@ -170,7 +169,7 @@
             if (Float.isNaN(v)) {
                 int id = fromNaN(v);
                 if ((id & NanMap.ID_REGION_MASK) != NanMap.ID_REGION_ARRAY) {
-                    sp = mOps[id - OFFSET].eval(sp);
+                    sp = opEval(sp, id);
                 } else {
                     mStack[++sp] = v;
                 }
@@ -199,7 +198,7 @@
             if (Float.isNaN(v)) {
                 int id = fromNaN(v);
                 if ((id & NanMap.ID_REGION_MASK) != NanMap.ID_REGION_ARRAY) {
-                    sp = mOps[id - OFFSET].eval(sp);
+                    sp = opEval(sp, id);
                 } else {
                     mStack[++sp] = v;
                 }
@@ -228,10 +227,11 @@
         mStack = mLocalStack;
         mVar = var;
         int sp = -1;
+
         for (int i = 0; i < len; i++) {
             float v = mStack[i];
             if (Float.isNaN(v)) {
-                sp = mOps[fromNaN(v) - OFFSET].eval(sp);
+                sp = opEval(sp, fromNaN(v));
             } else {
                 mStack[++sp] = v;
             }
@@ -250,9 +250,10 @@
         mStack = exp;
         mVar = var;
         int sp = -1;
+
         for (float v : exp) {
             if (Float.isNaN(v)) {
-                sp = mOps[fromNaN(v) - OFFSET].eval(sp);
+                sp = opEval(sp, fromNaN(v));
             } else {
                 System.out.print(" " + v);
                 mStack[++sp] = v;
@@ -261,294 +262,6 @@
         return mStack[sp];
     }
 
-    @NonNull Op[] mOps;
-
-    {
-        Op mADD =
-                (sp) -> { // ADD
-                    mStack[sp - 1] = mStack[sp - 1] + mStack[sp];
-                    return sp - 1;
-                };
-        Op mSUB =
-                (sp) -> { // SUB
-                    mStack[sp - 1] = mStack[sp - 1] - mStack[sp];
-                    return sp - 1;
-                };
-        Op mMUL =
-                (sp) -> { // MUL
-                    mStack[sp - 1] = mStack[sp - 1] * mStack[sp];
-                    return sp - 1;
-                };
-        Op mDIV =
-                (sp) -> { // DIV
-                    mStack[sp - 1] = mStack[sp - 1] / mStack[sp];
-                    return sp - 1;
-                };
-        Op mMOD =
-                (sp) -> { // MOD
-                    mStack[sp - 1] = mStack[sp - 1] % mStack[sp];
-                    return sp - 1;
-                };
-        Op mMIN =
-                (sp) -> { // MIN
-                    mStack[sp - 1] = (float) Math.min(mStack[sp - 1], mStack[sp]);
-                    return sp - 1;
-                };
-        Op mMAX =
-                (sp) -> { // MAX
-                    mStack[sp - 1] = (float) Math.max(mStack[sp - 1], mStack[sp]);
-                    return sp - 1;
-                };
-        Op mPOW =
-                (sp) -> { // POW
-                    mStack[sp - 1] = (float) Math.pow(mStack[sp - 1], mStack[sp]);
-                    return sp - 1;
-                };
-        Op mSQRT =
-                (sp) -> { // SQRT
-                    mStack[sp] = (float) Math.sqrt(mStack[sp]);
-                    return sp;
-                };
-        Op mABS =
-                (sp) -> { // ABS
-                    mStack[sp] = (float) Math.abs(mStack[sp]);
-                    return sp;
-                };
-        Op mSIGN =
-                (sp) -> { // SIGN
-                    mStack[sp] = (float) Math.signum(mStack[sp]);
-                    return sp;
-                };
-        Op mCOPY_SIGN =
-                (sp) -> { // copySign
-                    mStack[sp - 1] = (float) Math.copySign(mStack[sp - 1], mStack[sp]);
-                    return sp - 1;
-                };
-        Op mEXP =
-                (sp) -> { // EXP
-                    mStack[sp] = (float) Math.exp(mStack[sp]);
-                    return sp;
-                };
-        Op mFLOOR =
-                (sp) -> { // FLOOR
-                    mStack[sp] = (float) Math.floor(mStack[sp]);
-                    return sp;
-                };
-        Op mLOG =
-                (sp) -> { // LOG
-                    mStack[sp] = (float) Math.log10(mStack[sp]);
-                    return sp;
-                };
-        Op mLN =
-                (sp) -> { // LN
-                    mStack[sp] = (float) Math.log(mStack[sp]);
-                    return sp;
-                };
-        Op mROUND =
-                (sp) -> { // ROUND
-                    mStack[sp] = (float) Math.round(mStack[sp]);
-                    return sp;
-                };
-        Op mSIN =
-                (sp) -> { // SIN
-                    mStack[sp] = (float) Math.sin(mStack[sp]);
-                    return sp;
-                };
-        Op mCOS =
-                (sp) -> { // COS
-                    mStack[sp] = (float) Math.cos(mStack[sp]);
-                    return sp;
-                };
-        Op mTAN =
-                (sp) -> { // TAN
-                    mStack[sp] = (float) Math.tan(mStack[sp]);
-                    return sp;
-                };
-        Op mASIN =
-                (sp) -> { // ASIN
-                    mStack[sp] = (float) Math.asin(mStack[sp]);
-                    return sp;
-                };
-        Op mACOS =
-                (sp) -> { // ACOS
-                    mStack[sp] = (float) Math.acos(mStack[sp]);
-                    return sp;
-                };
-        Op mATAN =
-                (sp) -> { // ATAN
-                    mStack[sp] = (float) Math.atan(mStack[sp]);
-                    return sp;
-                };
-        Op mATAN2 =
-                (sp) -> { // ATAN2
-                    mStack[sp - 1] = (float) Math.atan2(mStack[sp - 1], mStack[sp]);
-                    return sp - 1;
-                };
-        Op mMAD =
-                (sp) -> { // MAD
-                    mStack[sp - 2] = mStack[sp] + mStack[sp - 1] * mStack[sp - 2];
-                    return sp - 2;
-                };
-        Op mTERNARY_CONDITIONAL =
-                (sp) -> { // TERNARY_CONDITIONAL
-                    mStack[sp - 2] = (mStack[sp] > 0) ? mStack[sp - 1] : mStack[sp - 2];
-                    return sp - 2;
-                };
-        Op mCLAMP =
-                (sp) -> { // CLAMP (min, max, value)
-                    mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]), mStack[sp - 1]);
-                    return sp - 2;
-                };
-        Op mCBRT =
-                (sp) -> { // CBRT is cube root
-                    mStack[sp] = (float) Math.pow(mStack[sp], 1 / 3.);
-                    return sp;
-                };
-        Op mDEG =
-                (sp) -> { // DEG
-                    mStack[sp] = mStack[sp] * FP_TO_RAD;
-                    return sp;
-                };
-        Op mRAD =
-                (sp) -> { // RAD
-                    mStack[sp] = mStack[sp] * FP_TO_DEG;
-                    return sp;
-                };
-        Op mCEIL =
-                (sp) -> { // CEIL
-                    mStack[sp] = (float) Math.ceil(mStack[sp]);
-                    return sp;
-                };
-        Op mA_DEREF =
-                (sp) -> { // A_DEREF
-                    Utils.log(" \n >>> DREF " + Integer.toHexString(fromNaN(mStack[sp - 1])));
-                    Utils.log(" >>> DREF " + mStack[sp] + "  " + mStack[sp - 1]);
-                    int id = fromNaN(mStack[sp - 1]);
-                    mStack[sp - 1] = mCollectionsAccess.getFloatValue(id, (int) mStack[sp]);
-                    return sp - 1;
-                };
-        Op mA_MAX =
-                (sp) -> { // A_MAX
-                    int id = fromNaN(mStack[sp]);
-                    float[] array = mCollectionsAccess.getFloats(id);
-                    float max = array[0];
-                    for (int i = 1; i < array.length; i++) {
-                        max = Math.max(max, array[i]);
-                    }
-                    mStack[sp] = max;
-                    return sp;
-                };
-        Op mA_MIN =
-                (sp) -> { // A_MIN
-                    int id = fromNaN(mStack[sp]);
-                    float[] array = mCollectionsAccess.getFloats(id);
-                    if (array.length == 0) {
-                        return sp;
-                    }
-                    float min = array[0];
-                    for (int i = 1; i < array.length; i++) {
-                        min = Math.min(min, array[i]);
-                    }
-                    mStack[sp] = min;
-                    return sp;
-                };
-        Op mA_SUM =
-                (sp) -> { // A_SUM
-                    int id = fromNaN(mStack[sp]);
-                    float[] array = mCollectionsAccess.getFloats(id);
-                    float sum = 0;
-                    for (int i = 0; i < array.length; i++) {
-                        sum += array[i];
-                    }
-                    mStack[sp] = sum;
-                    return sp;
-                };
-        Op mA_AVG =
-                (sp) -> { // A_AVG
-                    int id = fromNaN(mStack[sp]);
-                    float[] array = mCollectionsAccess.getFloats(id);
-                    float sum = 0;
-                    for (int i = 0; i < array.length; i++) {
-                        sum += array[i];
-                    }
-                    mStack[sp] = sum / array.length;
-                    return sp;
-                };
-        Op mA_LEN =
-                (sp) -> { // A_LEN
-                    int id = fromNaN(mStack[sp]);
-                    mStack[sp] = mCollectionsAccess.getListLength(id);
-                    return sp;
-                };
-        Op mA_SPLINE =
-                (sp) -> { // A_SPLINE
-                    int id = fromNaN(mStack[sp - 1]);
-                    mStack[sp - 1] = getSplineValue(id, mStack[sp]);
-                    return sp - 1;
-                };
-        Op mFIRST_VAR =
-                (sp) -> { // FIRST_VAR
-                    mStack[sp] = mVar[0];
-                    return sp;
-                };
-        Op mSECOND_VAR =
-                (sp) -> { // SECOND_VAR
-                    mStack[sp] = mVar[1];
-                    return sp;
-                };
-        Op mTHIRD_VAR =
-                (sp) -> { // THIRD_VAR
-                    mStack[sp] = mVar[2];
-                    return sp;
-                };
-
-        Op[] ops = {
-            null,
-            mADD,
-            mSUB,
-            mMUL,
-            mDIV,
-            mMOD,
-            mMIN,
-            mMAX,
-            mPOW,
-            mSQRT,
-            mABS,
-            mSIGN,
-            mCOPY_SIGN,
-            mEXP,
-            mFLOOR,
-            mLOG,
-            mLN,
-            mROUND,
-            mSIN,
-            mCOS,
-            mTAN,
-            mASIN,
-            mACOS,
-            mATAN,
-            mATAN2,
-            mMAD,
-            mTERNARY_CONDITIONAL,
-            mCLAMP,
-            mCBRT,
-            mDEG,
-            mRAD,
-            mCEIL,
-            mA_DEREF,
-            mA_MAX,
-            mA_MIN,
-            mA_SUM,
-            mA_AVG,
-            mA_LEN,
-            mA_SPLINE,
-            mFIRST_VAR,
-            mSECOND_VAR,
-            mTHIRD_VAR,
-        };
-        mOps = ops;
-    }
-
     static {
         int k = 0;
         sNames.put(k++, "NOP");
@@ -765,4 +478,248 @@
         int b = Float.floatToRawIntBits(v);
         return b & 0x7FFFFF;
     }
+
+    // ================= New approach ========
+    private static final int OP_ADD = OFFSET + 1;
+    private static final int OP_SUB = OFFSET + 2;
+    private static final int OP_MUL = OFFSET + 3;
+    private static final int OP_DIV = OFFSET + 4;
+    private static final int OP_MOD = OFFSET + 5;
+    private static final int OP_MIN = OFFSET + 6;
+    private static final int OP_MAX = OFFSET + 7;
+    private static final int OP_POW = OFFSET + 8;
+    private static final int OP_SQRT = OFFSET + 9;
+    private static final int OP_ABS = OFFSET + 10;
+    private static final int OP_SIGN = OFFSET + 11;
+    private static final int OP_COPY_SIGN = OFFSET + 12;
+    private static final int OP_EXP = OFFSET + 13;
+    private static final int OP_FLOOR = OFFSET + 14;
+    private static final int OP_LOG = OFFSET + 15;
+    private static final int OP_LN = OFFSET + 16;
+    private static final int OP_ROUND = OFFSET + 17;
+    private static final int OP_SIN = OFFSET + 18;
+    private static final int OP_COS = OFFSET + 19;
+    private static final int OP_TAN = OFFSET + 20;
+    private static final int OP_ASIN = OFFSET + 21;
+    private static final int OP_ACOS = OFFSET + 22;
+    private static final int OP_ATAN = OFFSET + 23;
+    private static final int OP_ATAN2 = OFFSET + 24;
+    private static final int OP_MAD = OFFSET + 25;
+    private static final int OP_TERNARY_CONDITIONAL = OFFSET + 26;
+    private static final int OP_CLAMP = OFFSET + 27;
+    private static final int OP_CBRT = OFFSET + 28;
+    private static final int OP_DEG = OFFSET + 29;
+    private static final int OP_RAD = OFFSET + 30;
+    private static final int OP_CEIL = OFFSET + 31;
+    private static final int OP_A_DEREF = OFFSET + 32;
+    private static final int OP_A_MAX = OFFSET + 33;
+    private static final int OP_A_MIN = OFFSET + 34;
+    private static final int OP_A_SUM = OFFSET + 35;
+    private static final int OP_A_AVG = OFFSET + 36;
+    private static final int OP_A_LEN = OFFSET + 37;
+    private static final int OP_A_SPLINE = OFFSET + 38;
+    private static final int OP_FIRST_VAR = OFFSET + 39;
+    private static final int OP_SECOND_VAR = OFFSET + 40;
+    private static final int OP_THIRD_VAR = OFFSET + 41;
+
+    int opEval(int sp, int id) {
+        float[] array;
+
+        switch (id) {
+            case OP_ADD:
+                mStack[sp - 1] = mStack[sp - 1] + mStack[sp];
+                return sp - 1;
+
+            case OP_SUB:
+                mStack[sp - 1] = mStack[sp - 1] - mStack[sp];
+                return sp - 1;
+
+            case OP_MUL:
+                mStack[sp - 1] = mStack[sp - 1] * mStack[sp];
+                return sp - 1;
+
+            case OP_DIV:
+                mStack[sp - 1] = mStack[sp - 1] / mStack[sp];
+                return sp - 1;
+
+            case OP_MOD:
+                mStack[sp - 1] = mStack[sp - 1] % mStack[sp];
+                return sp - 1;
+
+            case OP_MIN:
+                mStack[sp - 1] = (float) Math.min(mStack[sp - 1], mStack[sp]);
+                return sp - 1;
+
+            case OP_MAX:
+                mStack[sp - 1] = (float) Math.max(mStack[sp - 1], mStack[sp]);
+                return sp - 1;
+
+            case OP_POW:
+                mStack[sp - 1] = (float) Math.pow(mStack[sp - 1], mStack[sp]);
+                return sp - 1;
+
+            case OP_SQRT:
+                mStack[sp] = (float) Math.sqrt(mStack[sp]);
+                return sp;
+
+            case OP_ABS:
+                mStack[sp] = (float) Math.abs(mStack[sp]);
+                return sp;
+
+            case OP_SIGN:
+                mStack[sp] = (float) Math.signum(mStack[sp]);
+                return sp;
+
+            case OP_COPY_SIGN:
+                mStack[sp - 1] = (float) Math.copySign(mStack[sp - 1], mStack[sp]);
+                return sp - 1;
+
+            case OP_EXP:
+                mStack[sp] = (float) Math.exp(mStack[sp]);
+                return sp;
+
+            case OP_FLOOR:
+                mStack[sp] = (float) Math.floor(mStack[sp]);
+                return sp;
+
+            case OP_LOG:
+                mStack[sp] = (float) Math.log10(mStack[sp]);
+                return sp;
+
+            case OP_LN:
+                mStack[sp] = (float) Math.log(mStack[sp]);
+                return sp;
+
+            case OP_ROUND:
+                mStack[sp] = (float) Math.round(mStack[sp]);
+                return sp;
+
+            case OP_SIN:
+                mStack[sp] = (float) Math.sin(mStack[sp]);
+                return sp;
+
+            case OP_COS:
+                mStack[sp] = (float) Math.cos(mStack[sp]);
+                return sp;
+
+            case OP_TAN:
+                mStack[sp] = (float) Math.tan(mStack[sp]);
+                return sp;
+
+            case OP_ASIN:
+                mStack[sp] = (float) Math.asin(mStack[sp]);
+                return sp;
+
+            case OP_ACOS:
+                mStack[sp] = (float) Math.acos(mStack[sp]);
+                return sp;
+
+            case OP_ATAN:
+                mStack[sp] = (float) Math.atan(mStack[sp]);
+                return sp;
+
+            case OP_ATAN2:
+                mStack[sp - 1] = (float) Math.atan2(mStack[sp - 1], mStack[sp]);
+                return sp - 1;
+
+            case OP_MAD:
+                mStack[sp - 2] = mStack[sp] + mStack[sp - 1] * mStack[sp - 2];
+                return sp - 2;
+
+            case OP_TERNARY_CONDITIONAL:
+                mStack[sp - 2] = (mStack[sp] > 0) ? mStack[sp - 1] : mStack[sp - 2];
+                return sp - 2;
+
+            case OP_CLAMP:
+                mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]), mStack[sp - 1]);
+                return sp - 2;
+
+            case OP_CBRT:
+                mStack[sp] = (float) Math.pow(mStack[sp], 1 / 3.);
+                return sp;
+
+            case OP_DEG:
+                mStack[sp] = mStack[sp] * FP_TO_RAD;
+                return sp;
+
+            case OP_RAD:
+                mStack[sp] = mStack[sp] * FP_TO_DEG;
+                return sp;
+
+            case OP_CEIL:
+                mStack[sp] = (float) Math.ceil(mStack[sp]);
+                return sp;
+
+            case OP_A_DEREF:
+                id = fromNaN(mStack[sp - 1]);
+                mStack[sp - 1] = mCollectionsAccess.getFloatValue(id, (int) mStack[sp]);
+                return sp - 1;
+
+            case OP_A_MAX:
+                id = fromNaN(mStack[sp]);
+                array = mCollectionsAccess.getFloats(id);
+                float max = array[0];
+                for (int i = 1; i < array.length; i++) {
+                    max = Math.max(max, array[i]);
+                }
+                mStack[sp] = max;
+                return sp;
+
+            case OP_A_MIN:
+                id = fromNaN(mStack[sp]);
+                array = mCollectionsAccess.getFloats(id);
+                if (array.length == 0) {
+                    return sp;
+                }
+                float min = array[0];
+                for (int i = 1; i < array.length; i++) {
+                    min = Math.min(min, array[i]);
+                }
+                mStack[sp] = min;
+                return sp;
+
+            case OP_A_SUM:
+                id = fromNaN(mStack[sp]);
+                array = mCollectionsAccess.getFloats(id);
+                float sum = 0;
+                for (int i = 0; i < array.length; i++) {
+                    sum += array[i];
+                }
+                mStack[sp] = sum;
+                return sp;
+
+            case OP_A_AVG:
+                id = fromNaN(mStack[sp]);
+                array = mCollectionsAccess.getFloats(id);
+                sum = 0;
+                for (int i = 0; i < array.length; i++) {
+                    sum += array[i];
+                }
+                mStack[sp] = sum / array.length;
+                return sp;
+
+            case OP_A_LEN:
+                id = fromNaN(mStack[sp]);
+                mStack[sp] = mCollectionsAccess.getListLength(id);
+                return sp;
+
+            case OP_A_SPLINE:
+                id = fromNaN(mStack[sp - 1]);
+                mStack[sp - 1] = getSplineValue(id, mStack[sp]);
+                return sp - 1;
+
+            case OP_FIRST_VAR:
+                mStack[sp] = mVar[0];
+                return sp;
+
+            case OP_SECOND_VAR:
+                mStack[sp] = mVar[1];
+                return sp;
+
+            case OP_THIRD_VAR:
+                mStack[sp] = mVar[2];
+                return sp;
+        }
+        return sp;
+    }
 }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/CollectionsAccess.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/CollectionsAccess.java
index 4f12872..b92f96f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/CollectionsAccess.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/CollectionsAccess.java
@@ -24,13 +24,39 @@
 public interface CollectionsAccess {
     float getFloatValue(int id, int index);
 
+    /**
+     * Get the array of float if it is a float array
+     *
+     * @param id the id of the float array
+     * @return
+     */
     @Nullable
     float[] getFloats(int id);
 
+    /**
+     * Get the number of entries in the list
+     *
+     * @param id the id of the list
+     * @return
+     */
     int getListLength(int id);
 
+    /**
+     * get the id of an entry if the list is a list of id's
+     *
+     * @param listId the list id
+     * @param index the index into the list
+     * @return
+     */
     int getId(int listId, int index);
 
+    /**
+     * Get the value as an integer
+     *
+     * @param listId the list id to access
+     * @param index the index into the list
+     * @return
+     */
     default int getIntValue(int listId, int index) {
         return (int) getFloatValue(listId, index);
     }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntegerExpressionEvaluator.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntegerExpressionEvaluator.java
index f73ab39..0a33511 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntegerExpressionEvaluator.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntegerExpressionEvaluator.java
@@ -82,7 +82,7 @@
         for (int i = 0; i < mStack.length; i++) {
             int v = mStack[i];
             if (((1 << i) & mask) != 0) {
-                sp = mOps[v - OFFSET].eval(sp);
+                sp = opEval(sp, v);
             } else {
                 mStack[++sp] = v;
             }
@@ -107,7 +107,7 @@
         for (int i = 0; i < len; i++) {
             int v = mStack[i];
             if (((1 << i) & mask) != 0) {
-                sp = mOps[v - OFFSET].eval(sp);
+                sp = opEval(sp, v);
             } else {
                 mStack[++sp] = v;
             }
@@ -130,7 +130,7 @@
         for (int i = 0; i < exp.length; i++) {
             int v = mStack[i];
             if (((1 << i) & opMask) != 0) {
-                sp = mOps[v - OFFSET].eval(sp);
+                sp = opEval(sp, v);
             } else {
                 mStack[++sp] = v;
             }
@@ -138,171 +138,140 @@
         return mStack[sp];
     }
 
-    @NonNull Op[] mOps;
+    private static final int OP_ADD = OFFSET + 1;
+    private static final int OP_SUB = OFFSET + 2;
+    private static final int OP_MUL = OFFSET + 3;
+    private static final int OP_DIV = OFFSET + 4;
+    private static final int OP_MOD = OFFSET + 5;
+    private static final int OP_SHL = OFFSET + 6;
+    private static final int OP_SHR = OFFSET + 7;
+    private static final int OP_USHR = OFFSET + 8;
+    private static final int OP_OR = OFFSET + 9;
+    private static final int OP_AND = OFFSET + 10;
+    private static final int OP_XOR = OFFSET + 11;
+    private static final int OP_COPY_SIGN = OFFSET + 12;
+    private static final int OP_MIN = OFFSET + 13;
+    private static final int OP_MAX = OFFSET + 14;
+    private static final int OP_NEG = OFFSET + 15;
+    private static final int OP_ABS = OFFSET + 16;
+    private static final int OP_INCR = OFFSET + 17;
+    private static final int OP_DECR = OFFSET + 18;
+    private static final int OP_NOT = OFFSET + 19;
+    private static final int OP_SIGN = OFFSET + 20;
+    private static final int OP_CLAMP = OFFSET + 21;
+    private static final int OP_TERNARY_CONDITIONAL = OFFSET + 22;
+    private static final int OP_MAD = OFFSET + 23;
+    private static final int OP_FIRST_VAR = OFFSET + 24;
+    private static final int OP_SECOND_VAR = OFFSET + 25;
+    private static final int OP_THIRD_VAR = OFFSET + 26;
 
-    {
-        Op mADD =
-                (sp) -> { // ADD
-                    mStack[sp - 1] = mStack[sp - 1] + mStack[sp];
-                    return sp - 1;
-                };
-        Op mSUB =
-                (sp) -> { // SUB
-                    mStack[sp - 1] = mStack[sp - 1] - mStack[sp];
-                    return sp - 1;
-                };
-        Op mMUL =
-                (sp) -> { // MUL
-                    mStack[sp - 1] = mStack[sp - 1] * mStack[sp];
-                    return sp - 1;
-                };
-        Op mDIV =
-                (sp) -> { // DIV
-                    mStack[sp - 1] = mStack[sp - 1] / mStack[sp];
-                    return sp - 1;
-                };
-        Op mMOD =
-                (sp) -> { // MOD
-                    mStack[sp - 1] = mStack[sp - 1] % mStack[sp];
-                    return sp - 1;
-                };
-        Op mSHL =
-                (sp) -> { // SHL
-                    mStack[sp - 1] = mStack[sp - 1] << mStack[sp];
-                    return sp - 1;
-                };
-        Op mSHR =
-                (sp) -> { // SHR
-                    mStack[sp - 1] = mStack[sp - 1] >> mStack[sp];
-                    return sp - 1;
-                };
-        Op mUSHR =
-                (sp) -> { // USHR
-                    mStack[sp - 1] = mStack[sp - 1] >>> mStack[sp];
-                    return sp - 1;
-                };
-        Op mOR =
-                (sp) -> { // OR
-                    mStack[sp - 1] = mStack[sp - 1] | mStack[sp];
-                    return sp - 1;
-                };
-        Op mAND =
-                (sp) -> { // AND
-                    mStack[sp - 1] = mStack[sp - 1] & mStack[sp];
-                    return sp - 1;
-                };
-        Op mXOR =
-                (sp) -> { // XOR
-                    mStack[sp - 1] = mStack[sp - 1] ^ mStack[sp];
-                    return sp - 1;
-                };
-        Op mCOPY_SIGN =
-                (sp) -> { // COPY_SIGN copy the sign via bit manipulation
-                    mStack[sp - 1] = (mStack[sp - 1] ^ (mStack[sp] >> 31)) - (mStack[sp] >> 31);
-                    return sp - 1;
-                };
-        Op mMIN =
-                (sp) -> { // MIN
-                    mStack[sp - 1] = Math.min(mStack[sp - 1], mStack[sp]);
-                    return sp - 1;
-                };
-        Op mMAX =
-                (sp) -> { // MAX
-                    mStack[sp - 1] = Math.max(mStack[sp - 1], mStack[sp]);
-                    return sp - 1;
-                };
-        Op mNEG =
-                (sp) -> { // NEG
-                    mStack[sp] = -mStack[sp];
-                    return sp;
-                };
-        Op mABS =
-                (sp) -> { // ABS
-                    mStack[sp] = Math.abs(mStack[sp]);
-                    return sp;
-                };
-        Op mINCR =
-                (sp) -> { // INCR
-                    mStack[sp] = mStack[sp] + 1;
-                    return sp;
-                };
-        Op mDECR =
-                (sp) -> { // DECR
-                    mStack[sp] = mStack[sp] - 1;
-                    return sp;
-                };
-        Op mNOT =
-                (sp) -> { // NOT
-                    mStack[sp] = ~mStack[sp];
-                    return sp;
-                };
-        Op mSIGN =
-                (sp) -> { // SIGN x<0 = -1,x==0 =  0 , x>0 = 1
-                    mStack[sp] = (mStack[sp] >> 31) | (-mStack[sp] >>> 31);
-                    return sp;
-                };
-        Op mCLAMP =
-                (sp) -> { // CLAMP(min,max, val)
-                    mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]), mStack[sp - 1]);
-                    return sp - 2;
-                };
-        Op mTERNARY_CONDITIONAL =
-                (sp) -> { // TERNARY_CONDITIONAL
-                    mStack[sp - 2] = (mStack[sp] > 0) ? mStack[sp - 1] : mStack[sp - 2];
-                    return sp - 2;
-                };
-        Op mMAD =
-                (sp) -> { // MAD
-                    mStack[sp - 2] = mStack[sp] + mStack[sp - 1] * mStack[sp - 2];
-                    return sp - 2;
-                };
-        Op mFIRST_VAR =
-                (sp) -> { // FIRST_VAR
-                    mStack[sp] = mVar[0];
-                    return sp;
-                };
-        Op mSECOND_VAR =
-                (sp) -> { // SECOND_VAR
-                    mStack[sp] = mVar[1];
-                    return sp;
-                };
-        Op mTHIRD_VAR =
-                (sp) -> { // THIRD_VAR
-                    mStack[sp] = mVar[2];
-                    return sp;
-                };
+    int opEval(int sp, int id) {
+        switch (id) {
+            case OP_ADD: // ADD
+                mStack[sp - 1] = mStack[sp - 1] + mStack[sp];
+                return sp - 1;
 
-        Op[] ops = {
-            null,
-            mADD,
-            mSUB,
-            mMUL,
-            mDIV,
-            mMOD,
-            mSHL,
-            mSHR,
-            mUSHR,
-            mOR,
-            mAND,
-            mXOR,
-            mCOPY_SIGN,
-            mMIN,
-            mMAX,
-            mNEG,
-            mABS,
-            mINCR,
-            mDECR,
-            mNOT,
-            mSIGN,
-            mCLAMP,
-            mTERNARY_CONDITIONAL,
-            mMAD,
-            mFIRST_VAR,
-            mSECOND_VAR,
-            mTHIRD_VAR,
-        };
+            case OP_SUB: // SUB
+                mStack[sp - 1] = mStack[sp - 1] - mStack[sp];
+                return sp - 1;
 
-        mOps = ops;
+            case OP_MUL: // MUL
+                mStack[sp - 1] = mStack[sp - 1] * mStack[sp];
+                return sp - 1;
+
+            case OP_DIV: // DIV
+                mStack[sp - 1] = mStack[sp - 1] / mStack[sp];
+                return sp - 1;
+
+            case OP_MOD: // MOD
+                mStack[sp - 1] = mStack[sp - 1] % mStack[sp];
+                return sp - 1;
+
+            case OP_SHL: // SHL
+                mStack[sp - 1] = mStack[sp - 1] << mStack[sp];
+                return sp - 1;
+
+            case OP_SHR: // SHR
+                mStack[sp - 1] = mStack[sp - 1] >> mStack[sp];
+                return sp - 1;
+
+            case OP_USHR: // USHR
+                mStack[sp - 1] = mStack[sp - 1] >>> mStack[sp];
+                return sp - 1;
+
+            case OP_OR: // OR
+                mStack[sp - 1] = mStack[sp - 1] | mStack[sp];
+                return sp - 1;
+
+            case OP_AND: // AND
+                mStack[sp - 1] = mStack[sp - 1] & mStack[sp];
+                return sp - 1;
+
+            case OP_XOR: // XOR
+                mStack[sp - 1] = mStack[sp - 1] ^ mStack[sp];
+                return sp - 1;
+
+            case OP_COPY_SIGN: // COPY_SIGN copy the sign via bit manipulation
+                mStack[sp - 1] = (mStack[sp - 1] ^ (mStack[sp] >> 31)) - (mStack[sp] >> 31);
+                return sp - 1;
+
+            case OP_MIN: // MIN
+                mStack[sp - 1] = Math.min(mStack[sp - 1], mStack[sp]);
+                return sp - 1;
+
+            case OP_MAX: // MAX
+                mStack[sp - 1] = Math.max(mStack[sp - 1], mStack[sp]);
+                return sp - 1;
+
+            case OP_NEG: // NEG
+                mStack[sp] = -mStack[sp];
+                return sp;
+
+            case OP_ABS: // ABS
+                mStack[sp] = Math.abs(mStack[sp]);
+                return sp;
+
+            case OP_INCR: // INCR
+                mStack[sp] = mStack[sp] + 1;
+                return sp;
+
+            case OP_DECR: // DECR
+                mStack[sp] = mStack[sp] - 1;
+                return sp;
+
+            case OP_NOT: // NOT
+                mStack[sp] = ~mStack[sp];
+                return sp;
+
+            case OP_SIGN: // SIGN x<0 = -1,x==0 =  0 , x>0 = 1
+                mStack[sp] = (mStack[sp] >> 31) | (-mStack[sp] >>> 31);
+                return sp;
+
+            case OP_CLAMP: // CLAMP(min,max, val)
+                mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]), mStack[sp - 1]);
+                return sp - 2;
+
+            case OP_TERNARY_CONDITIONAL: // TERNARY_CONDITIONAL
+                mStack[sp - 2] = (mStack[sp] > 0) ? mStack[sp - 1] : mStack[sp - 2];
+                return sp - 2;
+
+            case OP_MAD: // MAD
+                mStack[sp - 2] = mStack[sp] + mStack[sp - 1] * mStack[sp - 2];
+                return sp - 2;
+
+            case OP_FIRST_VAR: // FIRST_VAR
+                mStack[sp] = mVar[0];
+                return sp;
+
+            case OP_SECOND_VAR: // SECOND_VAR
+                mStack[sp] = mVar[1];
+                return sp;
+
+            case OP_THIRD_VAR: // THIRD_VAR
+                mStack[sp] = mVar[2];
+                return sp;
+        }
+        return 0;
     }
 
     static {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java
index 7e02bc9..c7e2442 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java
@@ -31,6 +31,11 @@
  * limitations under the License.
  */
 
+/**
+ * This computes an form of easing such that the values constrained to be consistent in velocity The
+ * easing function is also constrained by the configure To have: a maximum time to stop, a maximum
+ * velocity, a maximum acceleration
+ */
 public class VelocityEasing {
     private float mStartPos = 0;
     private float mStartV = 0;
@@ -46,6 +51,11 @@
     private boolean mOneDimension = true;
     private float mTotalEasingDuration = 0;
 
+    /**
+     * get the duration the easing will take
+     *
+     * @return the duration for the easing
+     */
     public float getDuration() {
         if (mEasing != null) {
             return mTotalEasingDuration;
@@ -53,6 +63,12 @@
         return mDuration;
     }
 
+    /**
+     * Get the velocity at time t
+     *
+     * @param t time in seconds
+     * @return the velocity units/second
+     */
     public float getV(float t) {
         if (mEasing == null) {
             for (int i = 0; i < mNumberOfStages; i++) {
@@ -71,6 +87,12 @@
         return (float) getEasingDiff((t - mStage[lastStages].mStartTime));
     }
 
+    /**
+     * Get the position t seconds after the configure
+     *
+     * @param t time in seconds
+     * @return the position at time t
+     */
     public float getPos(float t) {
         if (mEasing == null) {
             for (int i = 0; i < mNumberOfStages; i++) {
@@ -91,6 +113,7 @@
         return ret;
     }
 
+    @Override
     public String toString() {
         var s = " ";
         for (int i = 0; i < mNumberOfStages; i++) {
@@ -100,6 +123,17 @@
         return s;
     }
 
+    /**
+     * Configure the Velocity easing curve The system is in arbitrary units
+     *
+     * @param currentPos the current position
+     * @param destination the destination
+     * @param currentVelocity the current velocity units/seconds
+     * @param maxTime the max time to achieve position
+     * @param maxAcceleration the max acceleration units/s^2
+     * @param maxVelocity the maximum velocity
+     * @param easing End in using this easing curve
+     */
     public void config(
             float currentPos,
             float destination,
diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java
index 4af79f3..975213f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java
@@ -29,7 +29,7 @@
 import java.util.List;
 
 /** Used to represent a boolean */
-public class BooleanConstant implements Operation {
+public class BooleanConstant extends Operation {
     private static final int OP_CODE = Operations.DATA_BOOLEAN;
     private boolean mValue = false;
     private int mId;
@@ -73,6 +73,11 @@
         return "OrigamiBoolean";
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.DATA_BOOLEAN;
     }
@@ -90,6 +95,12 @@
         buffer.writeBoolean(value);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int id = buffer.readInt();
 
diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java
index 613e732..210a15a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java
@@ -29,7 +29,7 @@
 import java.util.List;
 
 /** Represents a single integer typically used for states or named for input into the system */
-public class IntegerConstant implements Operation {
+public class IntegerConstant extends Operation {
     private int mValue = 0;
     private int mId;
 
@@ -65,6 +65,11 @@
         return "IntegerConstant";
     }
 
+    /**
+     * The OP_CODE for this command
+     *
+     * @return the opcode
+     */
     public static int id() {
         return Operations.DATA_INT;
     }
@@ -82,6 +87,12 @@
         buffer.writeInt(value);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int id = buffer.readInt();
 
diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java
index 745caa3..9875c93 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java
@@ -29,7 +29,7 @@
 import java.util.List;
 
 /** Used to represent a long */
-public class LongConstant implements Operation {
+public class LongConstant extends Operation {
     private static final int OP_CODE = Operations.DATA_LONG;
     private long mValue;
     private int mId;
@@ -83,6 +83,12 @@
         buffer.writeLong(value);
     }
 
+    /**
+     * Read this operation and add it to the list of operations
+     *
+     * @param buffer the buffer to read
+     * @param operations the list of operations that will be added to
+     */
     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
         int id = buffer.readInt();
 
diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
index 648f7bf..19b4b36 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
@@ -659,4 +659,14 @@
         }
         mListener = null;
     }
+
+    /**
+     * This returns the amount of time in ms the player used to evalueate a pass it is averaged over
+     * a number of evaluations.
+     *
+     * @return time in ms
+     */
+    public float getEvalTime() {
+        return mInner.getEvalTime();
+    }
 }
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
index 3c91cff..bc7d5e1 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
@@ -529,6 +529,7 @@
                     @Override
                     public void setImageFilterQuality(int quality) {
                         Utils.log(" quality =" + quality);
+                        mPaint.setFilterBitmap(quality == 1);
                     }
 
                     @Override
@@ -711,20 +712,32 @@
     }
 
     @Override
+    public void tweenPath(int out, int path1, int path2, float tween) {
+        float[] p = getPathArray(path1, path2, tween);
+        AndroidRemoteContext androidContext = (AndroidRemoteContext) mContext;
+        androidContext.mRemoteComposeState.putPathData(out, p);
+    }
+
+    @Override
     public void reset() {
         mPaint.reset();
     }
 
     private Path getPath(int path1Id, int path2Id, float tween, float start, float end) {
+        return getPath(getPathArray(path1Id, path2Id, tween), start, end);
+    }
+
+    private float[] getPathArray(int path1Id, int path2Id, float tween) {
+        AndroidRemoteContext androidContext = (AndroidRemoteContext) mContext;
         if (tween == 0.0f) {
-            return getPath(path1Id, start, end);
+            return androidContext.mRemoteComposeState.getPathData(path1Id);
         }
         if (tween == 1.0f) {
-            return getPath(path2Id, start, end);
+            return androidContext.mRemoteComposeState.getPathData(path2Id);
         }
-        AndroidRemoteContext androidContext = (AndroidRemoteContext) mContext;
-        float[] data1 = (float[]) androidContext.mRemoteComposeState.getFromId(path1Id);
-        float[] data2 = (float[]) androidContext.mRemoteComposeState.getFromId(path2Id);
+
+        float[] data1 = androidContext.mRemoteComposeState.getPathData(path1Id);
+        float[] data2 = androidContext.mRemoteComposeState.getPathData(path2Id);
         float[] tmp = new float[data2.length];
         for (int i = 0; i < tmp.length; i++) {
             if (Float.isNaN(data1[i]) || Float.isNaN(data2[i])) {
@@ -733,6 +746,10 @@
                 tmp[i] = (data2[i] - data1[i]) * tween + data1[i];
             }
         }
+        return tmp;
+    }
+
+    private Path getPath(float[] tmp, float start, float end) {
         Path path = new Path();
         FloatsToPath.genPath(path, tmp, start, end);
         return path;
@@ -741,9 +758,9 @@
     private Path getPath(int id, float start, float end) {
         AndroidRemoteContext androidContext = (AndroidRemoteContext) mContext;
         Path path = new Path();
-        if (androidContext.mRemoteComposeState.containsId(id)) {
-            float[] data = (float[]) androidContext.mRemoteComposeState.getFromId(id);
-            FloatsToPath.genPath(path, data, start, end);
+        float[] pathData = androidContext.mRemoteComposeState.getPathData(id);
+        if (pathData != null) {
+            FloatsToPath.genPath(path, pathData, start, end);
         }
         return path;
     }
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java
index 77c2514..0fb0a28 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java
@@ -60,9 +60,12 @@
 
     @Override
     public void loadPathData(int instanceId, @NonNull float[] floatPath) {
-        if (!mRemoteComposeState.containsId(instanceId)) {
-            mRemoteComposeState.cacheData(instanceId, floatPath);
-        }
+        mRemoteComposeState.putPathData(instanceId, floatPath);
+    }
+
+    @Override
+    public float[] getPathData(int instanceId) {
+        return mRemoteComposeState.getPathData(instanceId);
     }
 
     static class VarName {
@@ -162,7 +165,7 @@
      * @param type the type of the data 0 = RGBA 8888, 1 = 888, 2 = 8 gray
      * @param width with of image to be loaded largest dimension is 32767
      * @param height height of image to be loaded
-     * @param bitmap a byte array containing the image information
+     * @param data a byte array containing the image information
      * @oaram imageId the id of the image
      */
     @Override
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
index 8f55f8a..ecfd13a 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
@@ -349,6 +349,27 @@
 
     private int mCount;
     private long mTime = System.nanoTime();
+    private long mDuration;
+    private boolean mEvalTime = false;
+
+    /**
+     * This returns the amount of time in ms the player used to evalueate a pass it is averaged over
+     * a number of evaluations.
+     *
+     * @return time in ms
+     */
+    public float getEvalTime() {
+        if (!mEvalTime) {
+            mEvalTime = true;
+            return 0.0f;
+        }
+        double avg = mDuration / (double) mCount;
+        if (mCount > 100) {
+            mDuration /= 2;
+            mCount /= 2;
+        }
+        return (float) (avg * 1E-6); // ms
+    }
 
     @Override
     protected void onDraw(Canvas canvas) {
@@ -356,6 +377,7 @@
         if (mDocument == null) {
             return;
         }
+        long start = mEvalTime ? System.nanoTime() : 0;
         mARContext.setAnimationEnabled(true);
         mARContext.currentTime = System.currentTimeMillis();
         mARContext.setDebug(mDebug);
@@ -376,5 +398,9 @@
         if (mDocument.needsRepaint() > 0) {
             invalidate();
         }
+        if (mEvalTime) {
+            mDuration += System.nanoTime() - start;
+            mCount++;
+        }
     }
 }
diff --git a/core/java/com/android/server/pm/pkg/AndroidPackage.java b/core/java/com/android/server/pm/pkg/AndroidPackage.java
index d05f5e3..70dd10f 100644
--- a/core/java/com/android/server/pm/pkg/AndroidPackage.java
+++ b/core/java/com/android/server/pm/pkg/AndroidPackage.java
@@ -875,6 +875,14 @@
     int getMemtagMode();
 
     /**
+     * @see ApplicationInfo#getPageSizeAppCompatFlags()
+     * @see R.styleable#AndroidManifestApplication_pageSizeCompat
+     * @hide
+     */
+    @ApplicationInfo.PageSizeAppCompatFlags
+    int getPageSizeAppCompatFlags();
+
+    /**
      * TODO(b/135203078): Make all the Bundles immutable (and non-null by shared empty reference?)
      * @see R.styleable#AndroidManifestMetaData
      * @hide
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 5c03c5c..e22d958 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -214,6 +214,7 @@
                 "android_media_ToneGenerator.cpp",
                 "android_hardware_Camera.cpp",
                 "android_hardware_camera2_CameraMetadata.cpp",
+                "android_hardware_camera2_CameraDevice.cpp",
                 "android_hardware_camera2_DngCreator.cpp",
                 "android_hardware_camera2_impl_CameraExtensionJpegProcessor.cpp",
                 "android_hardware_camera2_utils_SurfaceUtils.cpp",
@@ -304,7 +305,12 @@
                 "av-types-aidl-cpp",
                 "android.hardware.camera.device@3.2",
                 "camera_platform_flags_c_lib",
+                "android.hardware.common.fmq-V1-cpp",
+                "android.hardware.common-V2-cpp",
+                "android.hardware.common.fmq-V1-ndk",
+                "android.hardware.common-V2-ndk",
                 "libandroid_net",
+                "libfmq",
                 "libbattery",
                 "libnetdutils",
                 "libmemtrack",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 00a6297..ac187b0 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -77,6 +77,7 @@
 
 extern int register_android_hardware_Camera(JNIEnv *env);
 extern int register_android_hardware_camera2_CameraMetadata(JNIEnv *env);
+extern int register_android_hardware_camera2_CameraDevice(JNIEnv *env);
 extern int register_android_hardware_camera2_DngCreator(JNIEnv *env);
 extern int register_android_hardware_camera2_impl_CameraExtensionJpegProcessor(JNIEnv* env);
 extern int register_android_hardware_camera2_utils_SurfaceUtils(JNIEnv* env);
@@ -1623,6 +1624,7 @@
         REG_JNI(register_com_android_internal_util_VirtualRefBasePtr),
         REG_JNI(register_android_hardware_Camera),
         REG_JNI(register_android_hardware_camera2_CameraMetadata),
+        REG_JNI(register_android_hardware_camera2_CameraDevice),
         REG_JNI(register_android_hardware_camera2_DngCreator),
         REG_JNI(register_android_hardware_camera2_impl_CameraExtensionJpegProcessor),
         REG_JNI(register_android_hardware_camera2_utils_SurfaceUtils),
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index ded1a99..1e7bfe3 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -36,6 +36,8 @@
 
 namespace android {
 
+static constexpr bool kLogWeakReachableDeletedAssets = false;
+
 static struct overlayableinfo_offsets_t {
   jclass classObject;
   jmethodID constructor;
@@ -97,7 +99,7 @@
       if (useCount > 1) {
         ALOGW("ApkAssets: Deleting an object '%s' with %d > 1 strong and %d weak references",
               (*assets)->GetDebugName().c_str(), int(useCount), int(weakCount));
-      } else if (weakCount > 0) {
+      } else if constexpr (kLogWeakReachableDeletedAssets) if (weakCount > 0) {
         ALOGW("ApkAssets: Deleting an ApkAssets object '%s' with %d weak references",
               (*assets)->GetDebugName().c_str(), int(weakCount));
       }
diff --git a/core/jni/android_hardware_camera2_CameraDevice.cpp b/core/jni/android_hardware_camera2_CameraDevice.cpp
new file mode 100644
index 0000000..493c707
--- /dev/null
+++ b/core/jni/android_hardware_camera2_CameraDevice.cpp
@@ -0,0 +1,148 @@
+/*
+**
+** Copyright 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.
+*/
+
+// #define LOG_NDEBUG 0
+
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
+#include <memory>
+#define LOG_TAG "CameraDevice-JNI"
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <vector>
+
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include "android_os_Parcel.h"
+#include "core_jni_helpers.h"
+#include <android/binder_parcel_jni.h>
+#include <android/hardware/camera2/ICameraDeviceUser.h>
+#include <aidl/android/hardware/common/fmq/MQDescriptor.h>
+#include <aidl/android/hardware/common/fmq/SynchronizedReadWrite.h>
+#include <fmq/AidlMessageQueue.h>
+#include <camera/CameraMetadata.h>
+
+using namespace android;
+
+using ::android::AidlMessageQueue;
+using ResultMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+
+class FMQReader {
+    public:
+    FMQReader(MQDescriptor<int8_t, SynchronizedReadWrite> &resultMQ) {
+        mCaptureResultMetadataQueue = std::make_shared<ResultMetadataQueue>(resultMQ);
+    }
+    std::shared_ptr<CameraMetadata> readOneResultMetadata(long metadataSize);
+    private:
+    std::shared_ptr<ResultMetadataQueue> mCaptureResultMetadataQueue = nullptr;
+};
+
+std::shared_ptr<CameraMetadata> FMQReader::readOneResultMetadata(long metadataSize) {
+    ATRACE_CALL();
+    if (metadataSize == 0) {
+        return nullptr;
+    }
+    auto metadataVec = std::make_unique<int8_t []>(metadataSize);
+    bool read = mCaptureResultMetadataQueue->read(metadataVec.get(), metadataSize);
+    if (!read) {
+        ALOGE("%s capture metadata could't be read from fmq", __FUNCTION__);
+        return nullptr;
+    }
+
+    // Takes ownership of metadataVec, this doesn't copy
+    std::shared_ptr<CameraMetadata> retVal =
+            std::make_shared<CameraMetadata>(
+                    reinterpret_cast<camera_metadata_t *>(metadataVec.release()));
+    return retVal;
+}
+
+extern "C" {
+
+static jlong CameraDevice_createFMQReader(JNIEnv *env, jclass thiz,
+        jobject resultParcel) {
+    AParcel *resultAParcel = AParcel_fromJavaParcel(env, resultParcel);
+    if (resultAParcel == nullptr) {
+        ALOGE("%s: Error creating result parcel", __FUNCTION__);
+        return 0;
+    }
+    AParcel_setDataPosition(resultAParcel, 0);
+
+    MQDescriptor<int8_t, SynchronizedReadWrite> resultMQ;
+    if (resultMQ.readFromParcel(resultAParcel) != OK) {
+        ALOGE("%s: read from result parcel failed", __FUNCTION__);
+        return 0;
+    }
+    return reinterpret_cast<jlong>(new std::shared_ptr<FMQReader>(
+            new FMQReader(resultMQ)));
+}
+
+static std::shared_ptr<FMQReader>* FMQReader_getSharedPtr(jlong fmqReaderLongPtr) {
+    return reinterpret_cast<std::shared_ptr<FMQReader>* >(fmqReaderLongPtr);
+}
+
+static jlong CameraDevice_readResultMetadata(JNIEnv *env, jclass thiz, jlong ptr,
+        jlong metadataSize) {
+    ALOGV("%s", __FUNCTION__);
+
+    FMQReader *fmqReader = FMQReader_getSharedPtr(ptr)->get();
+    auto metadataSp = fmqReader->readOneResultMetadata(metadataSize);
+    auto retVal = new std::shared_ptr<CameraMetadata>(metadataSp);
+    return reinterpret_cast<jlong>(retVal);
+}
+
+static void CameraDevice_close(JNIEnv *env, jclass thiz, jlong ptr) {
+    ALOGV("%s", __FUNCTION__);
+
+    auto fmqPtr = FMQReader_getSharedPtr(ptr);
+    if (fmqPtr != nullptr) {
+        delete fmqPtr;
+    }
+}
+
+}
+
+//-------------------------------------------------
+#define CAMERA_DEVICE_CLASS_NAME "android/hardware/camera2/impl/CameraDeviceImpl"
+static const JNINativeMethod gCameraDeviceMethods[] = {
+// static methods
+  { "nativeCreateFMQReader",
+    "(Landroid/os/Parcel;)J",
+    (void *)CameraDevice_createFMQReader},
+  { "nativeReadResultMetadata",
+    "(JJ)J",
+    (void *)CameraDevice_readResultMetadata},
+  { "nativeClose",
+    "(J)V",
+    (void*)CameraDevice_close},
+// instance methods
+};
+
+
+// Get all the required offsets in java class and register native functions
+int register_android_hardware_camera2_CameraDevice(JNIEnv *env)
+{
+    // Register native functions
+    return RegisterMethodsOrDie(env,
+            CAMERA_DEVICE_CLASS_NAME,
+            gCameraDeviceMethods,
+            NELEM(gCameraDeviceMethods));
+}
+
+extern "C" {
+
+} // extern "C"
\ No newline at end of file
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 68e6420..0c243d1 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -119,6 +119,7 @@
     jfieldID renderFrameRate;
     jfieldID hasArrSupport;
     jfieldID frameRateCategoryRate;
+    jfieldID supportedRefreshRates;
     jfieldID supportedColorModes;
     jfieldID activeColorMode;
     jfieldID hdrCapabilities;
@@ -1508,6 +1509,21 @@
     env->SetBooleanField(object, gDynamicDisplayInfoClassInfo.hasArrSupport, info.hasArrSupport);
     env->SetObjectField(object, gDynamicDisplayInfoClassInfo.frameRateCategoryRate,
                         convertFrameRateCategoryRateToJavaObject(env, info.frameRateCategoryRate));
+
+    jfloatArray supportedRefreshRatesArray = env->NewFloatArray(info.supportedRefreshRates.size());
+    if (supportedRefreshRatesArray == NULL) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+        return NULL;
+    }
+    jfloat* supportedRefreshRatesArrayValues =
+            env->GetFloatArrayElements(supportedRefreshRatesArray, 0);
+    for (size_t i = 0; i < info.supportedRefreshRates.size(); i++) {
+        supportedRefreshRatesArrayValues[i] = static_cast<jfloat>(info.supportedRefreshRates[i]);
+    }
+    env->ReleaseFloatArrayElements(supportedRefreshRatesArray, supportedRefreshRatesArrayValues, 0);
+    env->SetObjectField(object, gDynamicDisplayInfoClassInfo.supportedRefreshRates,
+                        supportedRefreshRatesArray);
+
     jintArray colorModesArray = env->NewIntArray(info.supportedColorModes.size());
     if (colorModesArray == NULL) {
         jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
@@ -2766,6 +2782,8 @@
     gFrameRateCategoryRateClassInfo.ctor =
             GetMethodIDOrDie(env, frameRateCategoryRateClazz, "<init>", "(FF)V");
 
+    gDynamicDisplayInfoClassInfo.supportedRefreshRates =
+            GetFieldIDOrDie(env, dynamicInfoClazz, "supportedRefreshRates", "[F");
     gDynamicDisplayInfoClassInfo.supportedColorModes =
             GetFieldIDOrDie(env, dynamicInfoClazz, "supportedColorModes", "[I");
     gDynamicDisplayInfoClassInfo.activeColorMode =
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index 7ad18b8..b2eeff3 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -21,6 +21,7 @@
 #include <androidfw/ApkParsing.h>
 #include <androidfw/ZipFileRO.h>
 #include <androidfw/ZipUtils.h>
+#include <elf.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
@@ -38,6 +39,7 @@
 
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "com_android_internal_content_FileSystemUtils.h"
 #include "core_jni_helpers.h"
@@ -60,6 +62,12 @@
     NO_NATIVE_LIBRARIES = -114
 };
 
+// These code should match with PageSizeAppCompatFlags inside ApplicationInfo.java
+constexpr int PAGE_SIZE_APP_COMPAT_FLAG_ERROR = -1;
+constexpr int PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED = 0;
+constexpr int PAGE_SIZE_APP_COMPAT_FLAG_UNCOMPRESSED_LIBS_NOT_ALIGNED = 1 << 1;
+constexpr int PAGE_SIZE_APP_COMPAT_FLAG_ELF_NOT_ALIGNED = 1 << 2;
+
 typedef install_status_t (*iterFunc)(JNIEnv*, void*, ZipFileRO*, ZipEntryRO, const char*);
 
 static bool
@@ -524,11 +532,7 @@
     static const size_t kPageSize = getpagesize();
 
     // App compat is only applicable on 16kb-page-size devices.
-    if (kPageSize != 0x4000) {
-        return false;
-    }
-
-    return android::base::GetBoolProperty("bionic.linker.16kb.app_compat.enabled", false);
+    return kPageSize == 0x4000;
 }
 
 static jint
@@ -626,6 +630,166 @@
     return reinterpret_cast<jlong>(zipFile);
 }
 
+static jint checkLoadSegmentAlignment(const char* fileName, off64_t offset) {
+    std::vector<Elf64_Phdr> programHeaders;
+    if (!getLoadSegmentPhdrs(fileName, offset, programHeaders)) {
+        ALOGE("Failed to read program headers from ELF file.");
+        return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
+    }
+
+    int mode = PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED;
+    for (auto programHeader : programHeaders) {
+        if (programHeader.p_type != PT_LOAD) {
+            continue;
+        }
+
+        // Set ELF alignment bit if 4 KB aligned LOAD segment is found
+        if (programHeader.p_align == 0x1000) {
+            ALOGI("Setting page size compat mode PAGE_SIZE_APP_COMPAT_FLAG_ELF_NOT_ALIGNED");
+            mode |= PAGE_SIZE_APP_COMPAT_FLAG_ELF_NOT_ALIGNED;
+            break;
+        }
+    }
+
+    return mode;
+}
+
+static jint checkExtractedLibAlignment(ZipFileRO* zipFile, ZipEntryRO zipEntry,
+                                       const char* fileName, const std::string nativeLibPath) {
+    // Build local file path
+    const size_t fileNameLen = strlen(fileName);
+    char localFileName[nativeLibPath.size() + fileNameLen + 2];
+
+    if (strlcpy(localFileName, nativeLibPath.c_str(), sizeof(localFileName)) !=
+        nativeLibPath.size()) {
+        ALOGE("Couldn't allocate local file name for library");
+        return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
+    }
+
+    *(localFileName + nativeLibPath.size()) = '/';
+
+    if (strlcpy(localFileName + nativeLibPath.size() + 1, fileName,
+                sizeof(localFileName) - nativeLibPath.size() - 1) != fileNameLen) {
+        ALOGE("Couldn't allocate local file name for library");
+        return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
+    }
+
+    struct statfs64 fsInfo;
+    int result = statfs64(localFileName, &fsInfo);
+    if (result < 0) {
+        ALOGE("Failed to stat file :%s", localFileName);
+        return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
+    }
+
+    return checkLoadSegmentAlignment(localFileName, 0);
+}
+
+static jint checkAlignment(JNIEnv* env, jstring javaNativeLibPath, jboolean extractNativeLibs,
+                           ZipFileRO* zipFile, ZipEntryRO zipEntry, const char* fileName) {
+    int mode = PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED;
+    // Need two separate install status for APK and ELF alignment
+    static const size_t kPageSize = getpagesize();
+    jint ret = INSTALL_SUCCEEDED;
+
+    ScopedUtfChars nativeLibPath(env, javaNativeLibPath);
+    if (extractNativeLibs) {
+        ALOGI("extractNativeLibs specified, checking for extracted lib %s", fileName);
+        return checkExtractedLibAlignment(zipFile, zipEntry, fileName, nativeLibPath.c_str());
+    }
+
+    uint16_t method;
+    off64_t offset;
+    if (!zipFile->getEntryInfo(zipEntry, &method, nullptr, nullptr, &offset, nullptr, nullptr,
+                               nullptr)) {
+        ALOGE("Couldn't read zip entry info from zipFile %s", zipFile->getZipFileName());
+        return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
+    }
+
+    // check if library is uncompressed and page-aligned
+    if (method != ZipFileRO::kCompressStored) {
+        ALOGE("Library '%s' is compressed - will not be able to open it directly from apk.\n",
+              fileName);
+        return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
+    }
+
+    if (offset % kPageSize != 0) {
+        ALOGW("Library '%s' is not PAGE(%zu)-aligned - will not be able to open it directly "
+              "from apk.\n",
+              fileName, kPageSize);
+        mode |= PAGE_SIZE_APP_COMPAT_FLAG_UNCOMPRESSED_LIBS_NOT_ALIGNED;
+        ALOGI("Setting page size compat mode "
+              "PAGE_SIZE_APP_COMPAT_FLAG_UNCOMPRESSED_LIBS_NOT_ALIGNED for %s",
+              zipFile->getZipFileName());
+    }
+
+    int loadMode = checkLoadSegmentAlignment(zipFile->getZipFileName(), offset);
+    if (loadMode == PAGE_SIZE_APP_COMPAT_FLAG_ERROR) {
+        return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
+    }
+    mode |= loadMode;
+    return mode;
+}
+
+// TODO(b/371049373): This function is copy of iterateOverNativeFiles with different way of handling
+// and combining return values for all ELF and APKs. Find a way to consolidate two functions.
+static jint com_android_internal_content_NativeLibraryHelper_checkApkAlignment(
+        JNIEnv* env, jclass clazz, jlong apkHandle, jstring javaNativeLibPath, jstring javaCpuAbi,
+        jboolean extractNativeLibs, jboolean debuggable) {
+    int mode = PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED;
+    ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle);
+    if (zipFile == nullptr) {
+        ALOGE("zipfile handle is null");
+        return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
+    }
+
+    auto result = NativeLibrariesIterator::create(zipFile, debuggable);
+    if (!result.ok()) {
+        ALOGE("Can't iterate over native libs for file:%s", zipFile->getZipFileName());
+        return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
+    }
+    std::unique_ptr<NativeLibrariesIterator> it(std::move(result.value()));
+
+    const ScopedUtfChars cpuAbi(env, javaCpuAbi);
+    if (cpuAbi.c_str() == nullptr) {
+        ALOGE("cpuAbi is nullptr");
+        // This would've thrown, so this return code isn't observable by Java.
+        return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
+    }
+
+    while (true) {
+        auto next = it->next();
+        if (!next.ok()) {
+            ALOGE("next iterator not found Error:%d", next.error());
+            return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
+        }
+        auto entry = next.value();
+        if (entry == nullptr) {
+            break;
+        }
+
+        const char* fileName = it->currentEntry();
+        const char* lastSlash = it->lastSlash();
+
+        // Check to make sure the CPU ABI of this file is one we support.
+        const char* cpuAbiOffset = fileName + APK_LIB_LEN;
+        const size_t cpuAbiRegionSize = lastSlash - cpuAbiOffset;
+
+        if (cpuAbi.size() == cpuAbiRegionSize &&
+            !strncmp(cpuAbiOffset, cpuAbi.c_str(), cpuAbiRegionSize)) {
+            int ret = checkAlignment(env, javaNativeLibPath, extractNativeLibs, zipFile, entry,
+                                     lastSlash + 1);
+            if (ret == PAGE_SIZE_APP_COMPAT_FLAG_ERROR) {
+                ALOGE("Alignment check returned for zipfile: %s, entry:%s",
+                      zipFile->getZipFileName(), lastSlash + 1);
+                return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
+            }
+            mode |= ret;
+        }
+    }
+
+    return mode;
+}
+
 static void
 com_android_internal_content_NativeLibraryHelper_close(JNIEnv *env, jclass, jlong apkHandle)
 {
@@ -633,29 +797,23 @@
 }
 
 static const JNINativeMethod gMethods[] = {
-    {"nativeOpenApk",
-            "(Ljava/lang/String;)J",
-            (void *)com_android_internal_content_NativeLibraryHelper_openApk},
-    {"nativeOpenApkFd",
-            "(Ljava/io/FileDescriptor;Ljava/lang/String;)J",
-            (void *)com_android_internal_content_NativeLibraryHelper_openApkFd},
-    {"nativeClose",
-            "(J)V",
-            (void *)com_android_internal_content_NativeLibraryHelper_close},
-    {"nativeCopyNativeBinaries",
-            "(JLjava/lang/String;Ljava/lang/String;ZZ)I",
-            (void *)com_android_internal_content_NativeLibraryHelper_copyNativeBinaries},
-    {"nativeSumNativeBinaries",
-            "(JLjava/lang/String;Z)J",
-            (void *)com_android_internal_content_NativeLibraryHelper_sumNativeBinaries},
-    {"nativeFindSupportedAbi",
-            "(J[Ljava/lang/String;Z)I",
-            (void *)com_android_internal_content_NativeLibraryHelper_findSupportedAbi},
-    {"hasRenderscriptBitcode", "(J)I",
-            (void *)com_android_internal_content_NativeLibraryHelper_hasRenderscriptBitcode},
+        {"nativeOpenApk", "(Ljava/lang/String;)J",
+         (void*)com_android_internal_content_NativeLibraryHelper_openApk},
+        {"nativeOpenApkFd", "(Ljava/io/FileDescriptor;Ljava/lang/String;)J",
+         (void*)com_android_internal_content_NativeLibraryHelper_openApkFd},
+        {"nativeClose", "(J)V", (void*)com_android_internal_content_NativeLibraryHelper_close},
+        {"nativeCopyNativeBinaries", "(JLjava/lang/String;Ljava/lang/String;ZZ)I",
+         (void*)com_android_internal_content_NativeLibraryHelper_copyNativeBinaries},
+        {"nativeSumNativeBinaries", "(JLjava/lang/String;Z)J",
+         (void*)com_android_internal_content_NativeLibraryHelper_sumNativeBinaries},
+        {"nativeFindSupportedAbi", "(J[Ljava/lang/String;Z)I",
+         (void*)com_android_internal_content_NativeLibraryHelper_findSupportedAbi},
+        {"hasRenderscriptBitcode", "(J)I",
+         (void*)com_android_internal_content_NativeLibraryHelper_hasRenderscriptBitcode},
+        {"nativeCheckAlignment", "(JLjava/lang/String;Ljava/lang/String;ZZ)I",
+         (void*)com_android_internal_content_NativeLibraryHelper_checkApkAlignment},
 };
 
-
 int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env)
 {
     return RegisterMethodsOrDie(env,
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 284c299..aeaeeca 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -89,6 +89,7 @@
 
 #if defined(__BIONIC__)
 extern "C" void android_reset_stack_guards();
+extern "C" void android_set_16kb_appcompat_mode(bool enable_app_compat);
 #endif
 
 namespace {
@@ -350,6 +351,7 @@
     NATIVE_HEAP_ZERO_INIT_ENABLED = 1 << 23,
     PROFILEABLE = 1 << 24,
     DEBUG_ENABLE_PTRACE = 1 << 25,
+    ENABLE_PAGE_SIZE_APP_COMPAT = 1 << 26,
 };
 
 enum UnsolicitedZygoteMessageTypes : uint32_t {
@@ -2117,6 +2119,12 @@
     SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities,
                     fail_fn);
 
+    if ((runtime_flags & RuntimeFlags::ENABLE_PAGE_SIZE_APP_COMPAT) != 0) {
+        android_set_16kb_appcompat_mode(true);
+        // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART
+        // runtime.
+        runtime_flags &= ~RuntimeFlags::ENABLE_PAGE_SIZE_APP_COMPAT;
+    }
     __android_log_close();
     AStatsSocket_close();
 
diff --git a/core/proto/android/content/package_item_info.proto b/core/proto/android/content/package_item_info.proto
index b7408a4..facadee 100644
--- a/core/proto/android/content/package_item_info.proto
+++ b/core/proto/android/content/package_item_info.proto
@@ -114,6 +114,7 @@
         optional int32 enable_memtag = 20;
         optional bool native_heap_zero_init = 21;
         optional bool allow_cross_uid_activity_switch_from_below = 22;
+        optional int32 enable_page_size_app_compat = 23;
     }
     optional Detail detail = 17;
     repeated string overlay_paths = 18;
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 6af742f..2e0fe9e 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -256,6 +256,12 @@
     }
     optional Display display = 100;
 
+    message DoubleTapPowerButton {
+        optional SettingProto gesture_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto gesture = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional DoubleTapPowerButton double_tap_power_button = 103;
+
     message Doze {
         option (android.msg_privacy).dest = DEST_EXPLICIT;
 
@@ -737,5 +743,5 @@
 
     // Please insert fields in alphabetical order and group them into messages
     // if possible (to avoid reaching the method limit).
-    // Next tag = 103;
+    // Next tag = 104;
 }
diff --git a/core/res/Android.bp b/core/res/Android.bp
index 8042b30..aacd869 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -160,6 +160,7 @@
         "android.app.contextualsearch.flags-aconfig",
         "android.app.flags-aconfig",
         "android.appwidget.flags-aconfig",
+        "android.companion.virtualdevice.flags-aconfig",
         "android.content.pm.flags-aconfig",
         "android.media.audio-aconfig",
         "android.provider.flags-aconfig",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ead9b85..e2f3d2a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -848,10 +848,10 @@
     <protected-broadcast android:name="android.app.action.CONSOLIDATED_NOTIFICATION_POLICY_CHANGED" />
     <protected-broadcast android:name="android.intent.action.MAIN_USER_LOCKSCREEN_KNOWLEDGE_FACTOR_CHANGED" />
     <protected-broadcast android:name="com.android.uwb.uwbcountrycode.GEOCODE_RETRY" />
-    <protected-broadcast android:name="android.telephony.action.ACTION_SATELLITE_SUBSCRIBER_ID_LIST_CHANGED" />
+    <protected-broadcast android:name="android.telephony.satellite.action.SATELLITE_SUBSCRIBER_ID_LIST_CHANGED" />
     <protected-broadcast android:name="android.service.ondeviceintelligence.MODEL_LOADED" />
     <protected-broadcast android:name="android.service.ondeviceintelligence.MODEL_UNLOADED" />
-    <protected-broadcast android:name="android.telephony.action.ACTION_SATELLITE_START_NON_EMERGENCY_SESSION" />
+    <protected-broadcast android:name="android.telephony.satellite.action.SATELLITE_START_NON_EMERGENCY_SESSION" />
 
 
     <!-- ====================================================================== -->
@@ -4201,18 +4201,19 @@
                 android:protectionLevel="signature|installer" />
     <uses-permission android:name="android.permission.MANAGE_ENHANCED_CONFIRMATION_STATES" />
 
-    <!-- Allows an application to toggle the device's advanced protection mode status.
-        @FlaggedApi("android.security.aapm_api")
+    <!-- Allows an application to modify the device's advanced protection mode status, and query
+         the list of enabled features
+        @FlaggedApi(android.security.Flags.FLAG_AAPM_API)
         @SystemApi
         @hide -->
-    <permission android:name="android.permission.SET_ADVANCED_PROTECTION_MODE"
+    <permission android:name="android.permission.MANAGE_ADVANCED_PROTECTION_MODE"
         android:protectionLevel="signature|privileged"
         android:featureFlag="android.security.aapm_api"/>
-    <uses-permission android:name="android.permission.SET_ADVANCED_PROTECTION_MODE"
+    <uses-permission android:name="android.permission.MANAGE_ADVANCED_PROTECTION_MODE"
         android:featureFlag="android.security.aapm_api"/>
 
     <!-- Allows an application to query the device's advanced protection mode status.
-        @FlaggedApi("android.security.aapm_api") -->
+        @FlaggedApi(android.security.Flags.FLAG_AAPM_API) -->
     <permission android:name="android.permission.QUERY_ADVANCED_PROTECTION_MODE"
         android:protectionLevel="normal"
         android:featureFlag="android.security.aapm_api"/>
@@ -6515,7 +6516,7 @@
      @hide -->
     <permission android:name="android.permission.BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION"
         android:featureFlag="android.media.audio.concurrent_audio_record_bypass_permission"
-        android:protectionLevel="signature|privileged|role" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to capture audio for hotword detection.
          <p>Not for use by third-party applications.</p>
@@ -8059,6 +8060,13 @@
     <permission android:name="android.permission.ADD_ALWAYS_UNLOCKED_DISPLAY"
                 android:protectionLevel="signature|role"/>
 
+    <!-- Allows an application to create displays that mirror other displays' content.
+         @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ENABLE_LIMITED_VDM_ROLE)
+         @hide @SystemApi -->
+    <permission android:name="android.permission.ADD_MIRROR_DISPLAY"
+        android:protectionLevel="internal|role"
+        android:featureFlag="android.companion.virtualdevice.flags.enable_limited_vdm_role" />
+
     <!-- @hide @SystemApi Allows an application to access locusId events in the usage stats. -->
     <permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS"
                 android:protectionLevel="signature|role" />
@@ -9343,6 +9351,17 @@
             </intent-filter>
         </service>
 
+        <service android:name="com.android.ecm.EnhancedConfirmationCallTrackerService"
+            android:permission="android.permission.BIND_INCALL_SERVICE"
+            android:featureFlag="android.permission.flags.enhanced_confirmation_in_call_apis_enabled"
+            android:exported="true">
+            <meta-data android:name="android.telecom.INCLUDE_SELF_MANAGED_CALLS"
+                android:value="true" />
+            <intent-filter>
+                <action android:name="android.telecom.InCallService"/>
+            </intent-filter>
+        </service>
+
         <service android:name="com.android.server.companion.datatransfer.contextsync.CallMetadataSyncConnectionService"
                  android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
                  android:exported="true">
diff --git a/core/res/res/drawable-watch-v36/dialog_alert_button_background_negative.xml b/core/res/res/drawable-watch-v36/dialog_alert_button_background_negative.xml
index b6b8eac3..0314bbe 100644
--- a/core/res/res/drawable-watch-v36/dialog_alert_button_background_negative.xml
+++ b/core/res/res/drawable-watch-v36/dialog_alert_button_background_negative.xml
@@ -18,7 +18,7 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
     <solid android:color="@color/btn_material_filled_tonal_background_color"/>
-    <corners android:radius="@dimen/config_bottomDialogCornerRadius" />
+    <corners android:radius="@dimen/config_wearMaterial3_bottomDialogCornerRadius" />
     <size
         android:width="@dimen/dialog_btn_negative_width"
         android:height="@dimen/dialog_btn_negative_height" />
diff --git a/core/res/res/drawable-watch-v36/progress_ring_wear_material3.xml b/core/res/res/drawable-watch-v36/progress_ring_wear_material3.xml
new file mode 100644
index 0000000..5c0e5f6
--- /dev/null
+++ b/core/res/res/drawable-watch-v36/progress_ring_wear_material3.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<rotate xmlns:android="http://schemas.android.com/apk/res/android"
+        android:fromDegrees = "270"
+        android:toDegrees="270"
+        android:pivotX="50%"
+        android:pivotY="50%" >
+    <layer-list>
+        <item>
+            <shape
+                android:shape="ring"
+                android:innerRadiusRatio="@dimen/progressbar_inner_radius_ratio"
+                android:thickness="@dimen/progressbar_thickness"
+                android:useLevel="false">
+                <solid android:color="?attr/materialColorSurfaceContainer"/>
+            </shape>
+        </item>
+        <item>
+            <shape
+                android:shape="ring"
+                android:innerRadiusRatio="@dimen/progressbar_inner_radius_ratio"
+                android:thickness="@dimen/progressbar_thickness"
+                android:useLevel="true">
+                <solid android:color="?attr/materialColorPrimary"/>
+            </shape>
+        </item>
+    </layer-list>
+</rotate>
\ No newline at end of file
diff --git a/core/res/res/layout-sw600dp/preference_list_content_single.xml b/core/res/res/layout-sw600dp/preference_list_content_single.xml
index 88b1aa8..ebe4eca 100644
--- a/core/res/res/layout-sw600dp/preference_list_content_single.xml
+++ b/core/res/res/layout-sw600dp/preference_list_content_single.xml
@@ -19,6 +19,7 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
+    android:fitsSystemWindows="true"
     android:layout_height="match_parent"
     android:layout_width="match_parent">
 
diff --git a/core/res/res/layout-watch-v36/alert_dialog_icon_button_wear_material3.xml b/core/res/res/layout-watch-v36/alert_dialog_icon_button_wear_material3.xml
new file mode 100644
index 0000000..407ec7a
--- /dev/null
+++ b/core/res/res/layout-watch-v36/alert_dialog_icon_button_wear_material3.xml
@@ -0,0 +1,123 @@
+<!--
+  ~ 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.
+  -->
+
+<!-- This layout is the AlertDialog template. It overrides the system layout with the same name.
+    Make sure to include all the existing id of the overridden alert_dialog_material.-->
+<com.android.internal.widget.WatchListDecorLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/parentPanel"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <ScrollView
+        android:id="@+id/scrollView"
+        android:fillViewport="true"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+        <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+            <!-- Top Panel -->
+            <FrameLayout
+                android:paddingLeft="?dialogPreferredPadding"
+                android:paddingRight="?dialogPreferredPadding"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:id="@+id/topPanel"
+                android:minHeight="@dimen/dialog_list_padding_top_no_title">
+                <include android:id="@+id/title_template"
+                         android:layout_width="match_parent"
+                         android:layout_height="wrap_content"
+                         layout="@layout/alert_dialog_title_material"/>
+            </FrameLayout>
+
+            <!-- Content Panel -->
+            <FrameLayout android:id="@+id/contentPanel"
+                         android:layout_width="match_parent"
+                         android:layout_height="wrap_content"
+                         android:clipToPadding="false">
+                <TextView android:id="@+id/message"
+                          android:layout_width="match_parent"
+                          android:layout_height="wrap_content"
+                          android:gravity="center_horizontal|top"
+                          android:textAppearance="@style/TextAppearance.DeviceDefault.Body1"
+                          android:paddingStart="?dialogPreferredPadding"
+                          android:paddingEnd="?dialogPreferredPadding"
+                          android:paddingTop="8dip"
+                          android:paddingBottom="8dip"/>
+            </FrameLayout>
+
+            <!-- Custom Panel, to replace content panel if needed -->
+            <FrameLayout android:id="@+id/customPanel"
+                         android:layout_width="match_parent"
+                         android:layout_height="match_parent"
+                         android:minHeight="64dp">
+                <FrameLayout android:id="@+android:id/custom"
+                             android:layout_width="match_parent"
+                             android:layout_height="wrap_content" />
+            </FrameLayout>
+
+            <!-- Button Panel -->
+            <FrameLayout
+                android:id="@+id/buttonPanel"
+                android:minHeight="@dimen/dialog_list_padding_bottom_no_buttons"
+                android:layout_weight="1"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center">
+                <LinearLayout
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="bottom"
+                    android:orientation="horizontal"
+                    android:paddingBottom="?dialogPreferredPadding"
+                    style="?android:attr/buttonBarStyle"
+                    android:measureWithLargestChild="true">
+                    <Button android:id="@+id/button2"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_gravity="center"
+                            android:gravity="center"
+                            android:layout_weight="1"
+                            style="@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog.WearMaterial3.Negative" />
+                    <Button android:id="@+id/button3"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_gravity="center"
+                            android:gravity="center"
+                            android:layout_weight="1"
+                            style="?android:attr/buttonBarButtonStyle"/>
+                    <FrameLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content">
+                        <Button android:id="@+id/button1"
+                                android:layout_width="match_parent"
+                                android:layout_height="match_parent"
+                                android:layout_gravity="center"
+                                android:gravity="center"
+                                android:layout_weight="1"
+                                style="@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog.WearMaterial3.Confirm" />
+                        <!-- This works as background. -->
+                        <ImageView
+                            android:layout_width="match_parent"
+                            android:layout_height="match_parent"
+                            android:src="@drawable/dialog_alert_button_positive"/>
+                    </FrameLayout>
+                </LinearLayout>
+            </FrameLayout>
+        </LinearLayout>
+    </ScrollView>
+</com.android.internal.widget.WatchListDecorLayout>
diff --git a/core/res/res/layout-watch-v36/alert_dialog_material.xml b/core/res/res/layout-watch-v36/alert_dialog_material.xml
index 900102f..8f75456 100644
--- a/core/res/res/layout-watch-v36/alert_dialog_material.xml
+++ b/core/res/res/layout-watch-v36/alert_dialog_material.xml
@@ -82,9 +82,8 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_gravity="bottom"
-                    android:orientation="horizontal"
+                    android:orientation="vertical"
                     android:paddingBottom="?dialogPreferredPadding"
-                    style="?android:attr/buttonBarStyle"
                     android:measureWithLargestChild="true">
                     <Button android:id="@+id/button2"
                             android:layout_width="wrap_content"
@@ -92,7 +91,7 @@
                             android:layout_gravity="center"
                             android:gravity="center"
                             android:layout_weight="1"
-                            style="@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog.Negative" />
+                            style="@*android:style/Widget.DeviceDefault.Button.WearMaterial3"/>
                     <Button android:id="@+id/button3"
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
@@ -100,22 +99,13 @@
                             android:gravity="center"
                             android:layout_weight="1"
                             style="?android:attr/buttonBarButtonStyle"/>
-                    <FrameLayout
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content">
-                        <Button android:id="@+id/button1"
-                                android:layout_width="match_parent"
-                                android:layout_height="match_parent"
-                                android:layout_gravity="center"
-                                android:gravity="center"
-                                android:layout_weight="1"
-                                style="@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog.Confirm"/>
-                        <!-- This works as background. -->
-                        <ImageView
+                    <Button android:id="@+id/button1"
                             android:layout_width="match_parent"
                             android:layout_height="match_parent"
-                            android:src="@drawable/dialog_alert_button_positive"/>
-                    </FrameLayout>
+                            android:layout_gravity="center"
+                            android:gravity="center"
+                            android:layout_weight="1"
+                            style="@*android:style/Widget.DeviceDefault.Button.Filled"/>
                 </LinearLayout>
             </FrameLayout>
         </LinearLayout>
diff --git a/core/res/res/layout/notification_2025_conversation_face_pile_layout.xml b/core/res/res/layout/notification_2025_conversation_face_pile_layout.xml
new file mode 100644
index 0000000..b25adaa
--- /dev/null
+++ b/core/res/res/layout/notification_2025_conversation_face_pile_layout.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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 underthe License
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/conversation_face_pile"
+    android:layout_width="@dimen/conversation_avatar_size"
+    android:layout_height="@dimen/conversation_avatar_size"
+    android:forceHasOverlappingRendering="false"
+    >
+    <ImageView
+        android:id="@+id/conversation_face_pile_top"
+        android:layout_width="@dimen/messaging_avatar_size"
+        android:layout_height="@dimen/messaging_avatar_size"
+        android:scaleType="centerCrop"
+        android:layout_gravity="end|top"
+        android:background="@drawable/notification_icon_circle"
+        android:clipToOutline="true"
+        />
+    <FrameLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="start|bottom">
+        <ImageView
+            android:id="@+id/conversation_face_pile_bottom_background"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/conversation_badge_background"
+            />
+        <ImageView
+            android:id="@+id/conversation_face_pile_bottom"
+            android:layout_width="@dimen/messaging_avatar_size"
+            android:layout_height="@dimen/messaging_avatar_size"
+            android:scaleType="centerCrop"
+            android:layout_gravity="center"
+            android:background="@drawable/notification_icon_circle"
+            android:clipToOutline="true"
+            />
+    </FrameLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/notification_2025_conversation_icon_container.xml b/core/res/res/layout/notification_2025_conversation_icon_container.xml
new file mode 100644
index 0000000..90befd9
--- /dev/null
+++ b/core/res/res/layout/notification_2025_conversation_icon_container.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/conversation_icon_container"
+    android:layout_width="@dimen/conversation_content_start"
+    android:layout_height="wrap_content"
+    android:gravity="start|top"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:paddingTop="20dp"
+    android:paddingBottom="16dp"
+    android:importantForAccessibility="no"
+    >
+
+    <FrameLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:layout_gravity="top|center_horizontal"
+        >
+
+        <!-- Big icon: 48x48, 12dp padding top, 16dp padding sides -->
+        <com.android.internal.widget.CachingIconView
+            android:id="@+id/conversation_icon"
+            android:layout_width="@dimen/conversation_avatar_size"
+            android:layout_height="@dimen/conversation_avatar_size"
+            android:layout_marginLeft="@dimen/conversation_badge_protrusion"
+            android:layout_marginRight="@dimen/conversation_badge_protrusion"
+            android:layout_marginBottom="@dimen/conversation_badge_protrusion"
+            android:background="@drawable/notification_icon_circle"
+            android:clipToOutline="true"
+            android:scaleType="centerCrop"
+            android:importantForAccessibility="no"
+            />
+
+        <ViewStub
+            android:layout="@layout/notification_2025_conversation_face_pile_layout"
+            android:layout_width="@dimen/conversation_avatar_size"
+            android:layout_height="@dimen/conversation_avatar_size"
+            android:layout_marginLeft="@dimen/conversation_badge_protrusion"
+            android:layout_marginRight="@dimen/conversation_badge_protrusion"
+            android:layout_marginBottom="@dimen/conversation_badge_protrusion"
+            android:id="@+id/conversation_face_pile"
+            />
+
+        <FrameLayout
+            android:id="@+id/conversation_icon_badge"
+            android:layout_width="@dimen/conversation_icon_size_badged"
+            android:layout_height="@dimen/conversation_icon_size_badged"
+            android:layout_gravity="end|bottom"
+            android:clipChildren="false"
+            android:clipToPadding="false"
+            >
+
+            <com.android.internal.widget.CachingIconView
+                android:id="@+id/conversation_icon_badge_bg"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_gravity="center"
+                android:src="@drawable/conversation_badge_background"
+                android:forceHasOverlappingRendering="false"
+                android:scaleType="center"
+                />
+
+            <com.android.internal.widget.NotificationRowIconView
+                android:id="@+id/icon"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_margin="4dp"
+                android:layout_gravity="center"
+                android:forceHasOverlappingRendering="false"
+                />
+
+            <com.android.internal.widget.CachingIconView
+                android:id="@+id/conversation_icon_badge_ring"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:src="@drawable/conversation_badge_ring"
+                android:visibility="gone"
+                android:forceHasOverlappingRendering="false"
+                android:clipToPadding="false"
+                android:scaleType="center"
+                />
+        </FrameLayout>
+    </FrameLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/notification_2025_messaging_group.xml b/core/res/res/layout/notification_2025_messaging_group.xml
new file mode 100644
index 0000000..c1b491f
--- /dev/null
+++ b/core/res/res/layout/notification_2025_messaging_group.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+
+<!-- extends LinearLayout -->
+<com.android.internal.widget.MessagingGroup
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal" >
+    <FrameLayout
+        android:id="@+id/message_icon_container"
+        android:layout_width="@dimen/conversation_content_start"
+        android:layout_height="wrap_content">
+        <ImageView
+            android:layout_gravity="top|center_horizontal"
+            android:id="@+id/message_icon"
+            android:layout_width="@dimen/messaging_avatar_size"
+            android:layout_height="@dimen/messaging_avatar_size"
+            android:background="@drawable/notification_icon_circle"
+            android:clipToOutline="true"
+            android:scaleType="centerCrop"
+            android:importantForAccessibility="no" />
+    </FrameLayout>
+    <com.android.internal.widget.RemeasuringLinearLayout
+        android:id="@+id/messaging_group_content_container"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:baselineAligned="true"
+        android:orientation="vertical">
+        <com.android.internal.widget.ImageFloatingTextView
+            android:id="@+id/message_name"
+            style="@style/Widget.DeviceDefault.Notification.MessagingName"
+            android:layout_width="wrap_content"
+            android:textAlignment="viewStart"
+        />
+        <com.android.internal.widget.MessagingLinearLayout
+            android:id="@+id/group_message_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/notification_text_margin_top"
+            android:spacing="2dp" />
+    </com.android.internal.widget.RemeasuringLinearLayout>
+    <FrameLayout
+        android:id="@+id/messaging_group_icon_container"
+        android:layout_width="@dimen/messaging_avatar_size"
+        android:layout_height="@dimen/messaging_avatar_size"
+        android:layout_marginStart="12dp"
+        android:visibility="gone"/>
+    <FrameLayout
+        android:id="@+id/messaging_group_sending_progress_container"
+        android:layout_width="@dimen/messaging_group_sending_progress_size"
+        android:layout_height="@dimen/messaging_avatar_size"
+        android:layout_marginStart="12dp"
+        android:layout_gravity="top"
+        android:visibility="gone">
+        <ProgressBar
+            android:id="@+id/messaging_group_sending_progress"
+            android:layout_height="@dimen/messaging_group_sending_progress_size"
+            android:layout_width="@dimen/messaging_group_sending_progress_size"
+            android:layout_gravity="center"
+            android:indeterminate="true"
+            style="?android:attr/progressBarStyleSmall" />
+    </FrameLayout>
+</com.android.internal.widget.MessagingGroup>
diff --git a/core/res/res/layout/notification_2025_reply_container.xml b/core/res/res/layout/notification_2025_reply_container.xml
new file mode 100644
index 0000000..6923b59
--- /dev/null
+++ b/core/res/res/layout/notification_2025_reply_container.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+
+<!-- Note: this layout is included from a view stub; layout attributes will be overridden. -->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/notification_material_reply_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:paddingStart="@dimen/notification_2025_content_margin_start">
+
+    <ImageView
+            android:layout_width="match_parent"
+            android:layout_height="1dip"
+            android:id="@+id/action_divider"
+            android:layout_marginTop="@dimen/notification_content_margin"
+            android:layout_marginBottom="@dimen/notification_content_margin"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:background="@drawable/notification_template_divider" />
+
+    <TextView
+            android:id="@+id/notification_material_reply_text_3"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:visibility="gone"
+            android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Reply"
+            android:singleLine="true" />
+
+    <TextView
+            android:id="@+id/notification_material_reply_text_2"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:visibility="gone"
+            android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Reply"
+            android:singleLine="true" />
+
+    <LinearLayout
+            android:id="@+id/notification_material_reply_text_1_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:layout_marginEnd="@dimen/notification_content_margin_end">
+        <TextView
+                android:id="@+id/notification_material_reply_text_1"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:layout_marginEnd="@dimen/notification_content_margin_end"
+                android:layout_gravity="center"
+                android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Reply"
+                android:singleLine="true" />
+        <ProgressBar
+            android:id="@+id/notification_material_reply_progress"
+            android:layout_height="@dimen/messaging_group_sending_progress_size"
+            android:layout_width="@dimen/messaging_group_sending_progress_size"
+            android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+            android:layout_gravity="center"
+            android:indeterminate="true"
+            style="?android:attr/progressBarStyleSmall" />
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/core/res/res/layout/notification_2025_template_collapsed_base.xml b/core/res/res/layout/notification_2025_template_collapsed_base.xml
index c003820..09c02c9 100644
--- a/core/res/res/layout/notification_2025_template_collapsed_base.xml
+++ b/core/res/res/layout/notification_2025_template_collapsed_base.xml
@@ -20,7 +20,7 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_weight="1"
-    android:minHeight="@dimen/notification_headerless_min_height"
+    android:minHeight="@dimen/notification_2025_min_height"
     android:tag="base"
     >
 
@@ -72,8 +72,8 @@
             android:layout_height="wrap_content"
             android:layout_gravity="center_vertical"
             android:layout_weight="1"
-            android:layout_marginBottom="@dimen/notification_headerless_margin_twoline"
-            android:layout_marginTop="@dimen/notification_headerless_margin_twoline"
+            android:layout_marginBottom="@dimen/notification_2025_margin"
+            android:layout_marginTop="@dimen/notification_2025_margin"
             android:orientation="vertical"
             >
 
@@ -81,7 +81,7 @@
                 android:id="@+id/notification_top_line"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:minHeight="@dimen/notification_headerless_line_height"
+                android:minHeight="@dimen/notification_2025_content_min_height"
                 android:clipChildren="false"
                 android:theme="@style/Theme.DeviceDefault.Notification"
                 >
@@ -123,7 +123,7 @@
                     <!-- This is the simplest way to keep this text vertically centered without
                      gravity="center_vertical" which causes jumpiness in expansion animations. -->
                     <include
-                        layout="@layout/notification_template_text"
+                        layout="@layout/notification_2025_text"
                         android:layout_width="match_parent"
                         android:layout_height="@dimen/notification_text_height"
                         android:layout_gravity="center_vertical"
diff --git a/core/res/res/layout/notification_2025_template_collapsed_call.xml b/core/res/res/layout/notification_2025_template_collapsed_call.xml
new file mode 100644
index 0000000..614444d
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_collapsed_call.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ 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
+  -->
+
+<!-- Extends FrameLayout -->
+<com.android.internal.widget.CallLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:clipChildren="false"
+    android:tag="call"
+    android:theme="@style/Theme.DeviceDefault.Notification"
+    >
+
+    <!-- CallLayout shares visual appearance with ConversationLayout, so shares layouts -->
+    <include layout="@layout/notification_2025_conversation_icon_container" />
+
+    <LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="@dimen/notification_2025_min_height"
+        android:orientation="horizontal"
+        >
+
+        <LinearLayout
+            android:id="@+id/notification_main_column"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_marginStart="@dimen/conversation_content_start"
+            android:orientation="vertical"
+            android:paddingBottom="@dimen/notification_2025_margin"
+            >
+
+            <include
+                layout="@layout/notification_template_conversation_header"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                />
+
+            <include layout="@layout/notification_template_text"
+                android:layout_height="wrap_content"
+                android:minHeight="@dimen/notification_text_height"
+                />
+
+        </LinearLayout>
+
+        <FrameLayout
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:minWidth="@dimen/notification_content_margin_end"
+            >
+
+            <include
+                layout="@layout/notification_expand_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                />
+
+        </FrameLayout>
+
+    </LinearLayout>
+
+</com.android.internal.widget.CallLayout>
diff --git a/core/res/res/layout/notification_2025_template_collapsed_media.xml b/core/res/res/layout/notification_2025_template_collapsed_media.xml
new file mode 100644
index 0000000..f539105
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_collapsed_media.xml
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2014 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
+  -->
+
+<!-- Note: This is the old media style notification (different from UMO). -->
+
+<!-- extends FrameLayout -->
+<com.android.internal.widget.MediaNotificationView
+    android:id="@+id/status_bar_latest_event_content"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="@dimen/notification_2025_min_height"
+    android:tag="media"
+    >
+
+
+    <ImageView
+        android:id="@+id/left_icon"
+        android:layout_width="@dimen/notification_2025_left_icon_size"
+        android:layout_height="@dimen/notification_2025_left_icon_size"
+        android:layout_gravity="center_vertical|start"
+        android:layout_marginStart="@dimen/notification_left_icon_start"
+        android:background="@drawable/notification_large_icon_outline"
+        android:clipToOutline="true"
+        android:importantForAccessibility="no"
+        android:scaleType="centerCrop"
+        android:visibility="gone"
+        />
+
+    <com.android.internal.widget.NotificationRowIconView
+        android:id="@+id/icon"
+        android:layout_width="@dimen/notification_2025_icon_circle_size"
+        android:layout_height="@dimen/notification_2025_icon_circle_size"
+        android:layout_gravity="center_vertical|start"
+        android:layout_marginStart="@dimen/notification_icon_circle_start"
+        android:background="@drawable/notification_icon_circle"
+        android:padding="@dimen/notification_2025_icon_circle_padding"
+        />
+
+    <FrameLayout
+        android:id="@+id/alternate_expand_target"
+        android:layout_width="@dimen/notification_2025_content_margin_start"
+        android:layout_height="match_parent"
+        android:layout_gravity="start"
+        android:importantForAccessibility="no"
+        android:focusable="false"
+        />
+
+    <LinearLayout
+        android:id="@+id/notification_headerless_view_row"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+        android:orientation="horizontal"
+        >
+
+        <LinearLayout
+            android:id="@+id/notification_headerless_view_column"
+            android:layout_width="0px"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_weight="1"
+            android:layout_marginBottom="@dimen/notification_2025_margin"
+            android:layout_marginTop="@dimen/notification_2025_margin"
+            android:orientation="vertical"
+            >
+
+            <NotificationTopLineView
+                android:id="@+id/notification_top_line"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:minHeight="@dimen/notification_headerless_line_height"
+                android:clipChildren="false"
+                android:theme="@style/Theme.DeviceDefault.Notification"
+                >
+
+                <!--
+                NOTE: The notification_top_line_views layout contains the app_name_text.
+                In order to include the title view at the beginning, the Notification.Builder
+                has logic to hide that view whenever this title view is to be visible.
+                -->
+
+                <TextView
+                    android:id="@+id/title"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginEnd="@dimen/notification_header_separating_margin"
+                    android:ellipsize="end"
+                    android:fadingEdge="horizontal"
+                    android:singleLine="true"
+                    android:textAlignment="viewStart"
+                    android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
+                    />
+
+                <include layout="@layout/notification_top_line_views" />
+
+            </NotificationTopLineView>
+
+            <LinearLayout
+                android:id="@+id/notification_main_column"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                >
+
+                <com.android.internal.widget.NotificationVanishingFrameLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/notification_headerless_line_height"
+                    >
+                    <!-- This is the simplest way to keep this text vertically centered without
+                     gravity="center_vertical" which causes jumpiness in expansion animations. -->
+                    <include
+                        layout="@layout/notification_template_text"
+                        android:layout_width="match_parent"
+                        android:layout_height="@dimen/notification_text_height"
+                        android:layout_gravity="center_vertical"
+                        android:layout_marginTop="0dp"
+                        />
+                </com.android.internal.widget.NotificationVanishingFrameLayout>
+
+                <include
+                    layout="@layout/notification_template_progress"
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/notification_headerless_line_height"
+                    />
+
+            </LinearLayout>
+
+        </LinearLayout>
+
+        <ImageView
+            android:id="@+id/right_icon"
+            android:layout_width="@dimen/notification_right_icon_size"
+            android:layout_height="@dimen/notification_right_icon_size"
+            android:layout_gravity="center_vertical|end"
+            android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
+            android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
+            android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+            android:background="@drawable/notification_large_icon_outline"
+            android:clipToOutline="true"
+            android:importantForAccessibility="no"
+            android:scaleType="centerCrop"
+            />
+
+        <LinearLayout
+            android:id="@+id/media_actions"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layoutDirection="ltr"
+            android:orientation="horizontal"
+            >
+            <include
+                layout="@layout/notification_material_media_action"
+                android:id="@+id/action0"
+                />
+            <include
+                layout="@layout/notification_material_media_action"
+                android:id="@+id/action1"
+                />
+            <include
+                layout="@layout/notification_material_media_action"
+                android:id="@+id/action2"
+                />
+        </LinearLayout>
+
+        <FrameLayout
+            android:id="@+id/expand_button_touch_container"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:minWidth="@dimen/notification_content_margin_end"
+            >
+
+            <include layout="@layout/notification_expand_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical|end"
+                />
+
+        </FrameLayout>
+
+    </LinearLayout>
+</com.android.internal.widget.MediaNotificationView>
diff --git a/core/res/res/layout/notification_2025_template_collapsed_messaging.xml b/core/res/res/layout/notification_2025_template_collapsed_messaging.xml
new file mode 100644
index 0000000..ddf3ebc
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_collapsed_messaging.xml
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 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
+  -->
+
+<!-- Note: This is the old "Messaging Style" notification (not a conversation). -->
+
+<!-- extends FrameLayout -->
+<com.android.internal.widget.MessagingLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:clipChildren="false"
+    android:tag="messaging"
+    >
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:clipChildren="false"
+        android:orientation="vertical"
+        >
+
+
+        <com.android.internal.widget.NotificationMaxHeightFrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:minHeight="@dimen/notification_2025_min_height"
+            android:clipChildren="false"
+            >
+
+            <ImageView
+                android:id="@+id/left_icon"
+                android:layout_width="@dimen/notification_2025_left_icon_size"
+                android:layout_height="@dimen/notification_2025_left_icon_size"
+                android:layout_gravity="center_vertical|start"
+                android:layout_marginStart="@dimen/notification_left_icon_start"
+                android:background="@drawable/notification_large_icon_outline"
+                android:clipToOutline="true"
+                android:importantForAccessibility="no"
+                android:scaleType="centerCrop"
+                android:visibility="gone"
+                />
+
+            <com.android.internal.widget.NotificationRowIconView
+                android:id="@+id/icon"
+                android:layout_width="@dimen/notification_2025_icon_circle_size"
+                android:layout_height="@dimen/notification_2025_icon_circle_size"
+                android:layout_gravity="center_vertical|start"
+                android:layout_marginStart="@dimen/notification_icon_circle_start"
+                android:background="@drawable/notification_icon_circle"
+                android:padding="@dimen/notification_2025_icon_circle_padding"
+                />
+
+            <FrameLayout
+                android:id="@+id/alternate_expand_target"
+                android:layout_width="@dimen/notification_2025_content_margin_start"
+                android:layout_height="match_parent"
+                android:layout_gravity="start"
+                android:importantForAccessibility="no"
+                android:focusable="false"
+                />
+
+            <!--
+              NOTE: to make the expansion animation of id/notification_messaging happen vertically,
+              its X positioning must be the left edge of the notification, so instead of putting the
+              layout_marginStart on the id/notification_headerless_view_row, we put it on
+              id/notification_top_line, making the layout here just a bit different from the base.
+              -->
+            <LinearLayout
+                android:id="@+id/notification_headerless_view_row"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:orientation="horizontal"
+                android:clipChildren="false"
+                >
+
+                <!--
+                  NOTE: because messaging will always have 2 lines, this LinearLayout should NOT
+                  have the id/notification_headerless_view_column, as that is used for modifying
+                   vertical margins to accommodate the single-line state that base supports
+                  -->
+                <LinearLayout
+                    android:layout_width="0px"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center_vertical"
+                    android:layout_weight="1"
+                    android:layout_marginBottom="@dimen/notification_2025_margin"
+                    android:layout_marginTop="@dimen/notification_2025_margin"
+                    android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+                    android:clipChildren="false"
+                    android:orientation="vertical"
+                    >
+
+                    <NotificationTopLineView
+                        android:id="@+id/notification_top_line"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:minHeight="@dimen/notification_headerless_line_height"
+                        android:clipChildren="false"
+                        android:theme="@style/Theme.DeviceDefault.Notification"
+                        >
+
+                        <!--
+                        NOTE: The notification_top_line_views layout contains the app_name_text.
+                        In order to include the title view at the beginning, the Notification.Builder
+                        has logic to hide that view whenever this title view is to be visible.
+                        -->
+
+                        <TextView
+                            android:id="@+id/title"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_marginEnd="@dimen/notification_header_separating_margin"
+                            android:ellipsize="end"
+                            android:fadingEdge="horizontal"
+                            android:singleLine="true"
+                            android:textAlignment="viewStart"
+                            android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
+                            />
+
+                        <include layout="@layout/notification_top_line_views" />
+
+                    </NotificationTopLineView>
+
+                    <LinearLayout
+                        android:id="@+id/notification_main_column"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:clipChildren="false"
+                        >
+                        <com.android.internal.widget.MessagingLinearLayout
+                            android:id="@+id/notification_messaging"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:clipChildren="false"
+                            android:spacing="@dimen/notification_messaging_spacing" />
+                    </LinearLayout>
+
+                </LinearLayout>
+
+                <!-- Images -->
+                <com.android.internal.widget.MessagingLinearLayout
+                    android:id="@+id/conversation_image_message_container"
+                    android:layout_width="@dimen/notification_right_icon_size"
+                    android:layout_height="@dimen/notification_right_icon_size"
+                    android:layout_gravity="center_vertical|end"
+                    android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
+                    android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
+                    android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+                    android:forceHasOverlappingRendering="false"
+                    android:spacing="0dp"
+                    android:clipChildren="false"
+                    android:visibility="gone"
+                    />
+
+                <ImageView
+                    android:id="@+id/right_icon"
+                    android:layout_width="@dimen/notification_right_icon_size"
+                    android:layout_height="@dimen/notification_right_icon_size"
+                    android:layout_gravity="center_vertical|end"
+                    android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
+                    android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
+                    android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+                    android:background="@drawable/notification_large_icon_outline"
+                    android:clipToOutline="true"
+                    android:importantForAccessibility="no"
+                    android:scaleType="centerCrop"
+                    />
+
+                <FrameLayout
+                    android:id="@+id/expand_button_touch_container"
+                    android:layout_width="wrap_content"
+                    android:layout_height="match_parent"
+                    android:minWidth="@dimen/notification_content_margin_end"
+                    >
+
+                    <include layout="@layout/notification_expand_button"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_gravity="center_vertical|end"
+                        />
+
+                </FrameLayout>
+
+            </LinearLayout>
+
+        </com.android.internal.widget.NotificationMaxHeightFrameLayout>
+
+    <LinearLayout
+            android:id="@+id/notification_action_list_margin_target"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="-20dp"
+            android:clipChildren="false"
+            android:orientation="vertical">
+        <include layout="@layout/notification_template_smart_reply_container"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/notification_content_margin"
+                android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+                android:layout_marginEnd="@dimen/notification_content_margin_end" />
+        <include layout="@layout/notification_material_action_list" />
+    </LinearLayout>
+</LinearLayout>
+</com.android.internal.widget.MessagingLayout>
diff --git a/core/res/res/layout/notification_2025_template_conversation.xml b/core/res/res/layout/notification_2025_template_conversation.xml
new file mode 100644
index 0000000..0c4c7fb
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_conversation.xml
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+
+<!-- extends FrameLayout -->
+<com.android.internal.widget.ConversationLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:clipChildren="false"
+    android:tag="conversation"
+    android:theme="@style/Theme.DeviceDefault.Notification"
+    >
+
+    <include layout="@layout/notification_2025_conversation_icon_container" />
+
+    <!-- Wraps entire "expandable" notification -->
+    <com.android.internal.widget.RemeasuringLinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="top"
+        android:clipToPadding="false"
+        android:clipChildren="false"
+        android:orientation="vertical"
+        >
+        <!-- LinearLayout for Expand Button-->
+        <com.android.internal.widget.RemeasuringLinearLayout
+            android:id="@+id/expand_button_and_content_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:gravity="start|top"
+            android:orientation="horizontal"
+            android:clipChildren="false"
+            android:clipToPadding="false">
+            <!--TODO: move this into a separate layout and share logic with the header to bring back app opps etc-->
+            <com.android.internal.widget.RemeasuringLinearLayout
+                android:id="@+id/notification_action_list_margin_target"
+                android:layout_width="0dp"
+                android:orientation="vertical"
+                android:layout_height="wrap_content"
+                android:layout_weight="1">
+
+                <!-- Header -->
+
+                <!-- Use layout_marginStart instead of paddingStart to work around strange
+                     measurement behavior on lower display densities. -->
+                <include
+                    layout="@layout/notification_template_conversation_header"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginBottom="2dp"
+                    android:layout_marginStart="@dimen/conversation_content_start"
+                    />
+
+                <!-- Messages -->
+                <com.android.internal.widget.MessagingLinearLayout
+                    android:id="@+id/notification_messaging"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:minHeight="@dimen/notification_text_size"
+                    android:spacing="@dimen/notification_messaging_spacing"
+                    android:clipToPadding="false"
+                    android:clipChildren="false"
+                    />
+            </com.android.internal.widget.RemeasuringLinearLayout>
+
+            <!-- This is where the expand button container will be placed when collapsed-->
+        </com.android.internal.widget.RemeasuringLinearLayout>
+
+        <include layout="@layout/notification_template_smart_reply_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/notification_content_margin"
+            android:layout_marginStart="@dimen/conversation_content_start"
+            android:layout_marginEnd="@dimen/notification_content_margin_end" />
+        <include layout="@layout/notification_material_action_list" />
+    </com.android.internal.widget.RemeasuringLinearLayout>
+
+    <!--expand_button_a11y_container ensures talkback focus order is correct when view is expanded.
+    The -1px of marginTop and 1px of paddingTop make sure expand_button_a11y_container is prior to
+    its sibling view in accessibility focus order.
+    {see android.view.ViewGroup.addChildrenForAccessibility()}
+    expand_button_container will be moved under expand_button_and_content_container when collapsed,
+    this dynamic movement ensures message can flow under expand button when expanded-->
+    <FrameLayout
+        android:id="@+id/expand_button_a11y_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="end|top"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:layout_marginTop="-1px"
+        android:paddingTop="1px"
+        >
+        <!--expand_button_container is dynamically placed between here and at the end of the
+        layout. It starts here since only FrameLayout layout params have gravity-->
+        <LinearLayout
+            android:id="@+id/expand_button_container"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_gravity="end|top"
+            android:clipChildren="false"
+            android:clipToPadding="false"
+            android:orientation="vertical">
+            <include layout="@layout/notification_close_button"
+                android:layout_width="@dimen/notification_close_button_size"
+                android:layout_height="@dimen/notification_close_button_size"
+                android:layout_gravity="end"
+                android:layout_marginEnd="20dp"
+                />
+            <!--expand_button_touch_container makes sure that we can nicely center the expand
+            content in the collapsed layout while the parent makes sure that we're never laid out
+            bigger than the messaging content.-->
+            <LinearLayout
+                android:id="@+id/expand_button_touch_container"
+                android:layout_width="wrap_content"
+                android:layout_height="@dimen/conversation_expand_button_height"
+                android:orientation="horizontal"
+                android:layout_gravity="end|top"
+                android:paddingEnd="0dp"
+                android:clipToPadding="false"
+                android:clipChildren="false"
+                >
+                <!-- Images -->
+                <com.android.internal.widget.MessagingLinearLayout
+                    android:id="@+id/conversation_image_message_container"
+                    android:forceHasOverlappingRendering="false"
+                    android:layout_width="40dp"
+                    android:layout_height="40dp"
+                    android:layout_marginStart="@dimen/conversation_image_start_margin"
+                    android:spacing="0dp"
+                    android:layout_gravity="center"
+                    android:clipToPadding="false"
+                    android:clipChildren="false"
+                    />
+                <include layout="@layout/notification_expand_button"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    />
+            </LinearLayout>
+        </LinearLayout>
+    </FrameLayout>
+</com.android.internal.widget.ConversationLayout>
diff --git a/core/res/res/layout/notification_2025_template_expanded_base.xml b/core/res/res/layout/notification_2025_template_expanded_base.xml
new file mode 100644
index 0000000..e480fe5
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_expanded_base.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ 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
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:clipChildren="false"
+    android:tag="big"
+    >
+
+    <LinearLayout
+        android:id="@+id/notification_action_list_margin_target"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/notification_content_margin"
+        android:orientation="vertical"
+        >
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_gravity="top"
+            >
+
+            <include layout="@layout/notification_2025_template_header" />
+
+            <LinearLayout
+                android:id="@+id/notification_main_column"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+                android:layout_marginEnd="@dimen/notification_content_margin_end"
+                android:layout_marginTop="@dimen/notification_content_margin_top"
+                android:orientation="vertical"
+                >
+
+                <include layout="@layout/notification_template_part_line1" />
+
+                <include layout="@layout/notification_template_text_multiline" />
+
+                <include
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/notification_progress_bar_height"
+                    android:layout_marginTop="@dimen/notification_progress_margin_top"
+                    layout="@layout/notification_template_progress"
+                    />
+            </LinearLayout>
+
+            <include layout="@layout/notification_template_right_icon" />
+        </FrameLayout>
+
+        <ViewStub
+            android:layout="@layout/notification_2025_reply_container"
+            android:id="@+id/notification_material_reply_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            />
+
+        <include
+            layout="@layout/notification_template_smart_reply_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:layout_marginTop="@dimen/notification_content_margin"
+            />
+
+        <include layout="@layout/notification_material_action_list" />
+    </LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/notification_2025_template_expanded_big_picture.xml b/core/res/res/layout/notification_2025_template_expanded_big_picture.xml
new file mode 100644
index 0000000..18bafe0
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_expanded_big_picture.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ 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
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:tag="bigPicture"
+    android:clipChildren="false"
+    >
+
+    <include layout="@layout/notification_2025_template_header" />
+
+    <include layout="@layout/notification_template_right_icon" />
+
+    <LinearLayout
+        android:id="@+id/notification_action_list_margin_target"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="top"
+        android:layout_marginTop="@dimen/notification_content_margin_top"
+        android:clipToPadding="false"
+        android:orientation="vertical"
+        >
+
+        <LinearLayout
+            android:id="@+id/notification_main_column"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:orientation="vertical"
+            >
+
+            <include layout="@layout/notification_template_part_line1" />
+
+            <include
+                layout="@layout/notification_template_progress"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/notification_progress_bar_height"
+                android:layout_marginTop="@dimen/notification_progress_margin_top"
+                />
+
+            <include layout="@layout/notification_template_text_multiline" />
+        </LinearLayout>
+
+        <com.android.internal.widget.BigPictureNotificationImageView
+            android:id="@+id/big_picture"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:adjustViewBounds="true"
+            android:layout_weight="1"
+            android:layout_marginTop="13dp"
+            android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:background="@drawable/notification_big_picture_outline"
+            android:clipToOutline="true"
+            android:scaleType="centerCrop"
+            />
+
+        <ViewStub
+            android:layout="@layout/notification_material_reply_text"
+            android:id="@+id/notification_2025_reply_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            />
+
+        <include
+            layout="@layout/notification_template_smart_reply_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:layout_marginTop="@dimen/notification_content_margin"
+            />
+
+        <include layout="@layout/notification_material_action_list" />
+    </LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/notification_2025_template_expanded_big_text.xml b/core/res/res/layout/notification_2025_template_expanded_big_text.xml
new file mode 100644
index 0000000..9ff141b
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_expanded_big_text.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ 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
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:clipChildren="false"
+    android:tag="bigText"
+    >
+
+    <include layout="@layout/notification_2025_template_header" />
+
+    <com.android.internal.widget.RemeasuringLinearLayout
+        android:id="@+id/notification_action_list_margin_target"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="top"
+        android:layout_marginTop="@dimen/notification_content_margin_top"
+        android:layout_marginBottom="@dimen/notification_content_margin"
+        android:clipToPadding="false"
+        android:orientation="vertical"
+        >
+
+        <com.android.internal.widget.RemeasuringLinearLayout
+            android:id="@+id/notification_main_column"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top"
+            android:paddingStart="@dimen/notification_2025_content_margin_start"
+            android:paddingEnd="@dimen/notification_content_margin_end"
+            android:clipToPadding="false"
+            android:orientation="vertical"
+            android:layout_weight="1"
+            >
+
+            <include layout="@layout/notification_template_part_line1" />
+
+            <include
+                layout="@layout/notification_template_progress"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/notification_progress_bar_height"
+                android:layout_marginTop="@dimen/notification_progress_margin_top"
+                android:layout_marginBottom="6dp"
+                />
+
+            <com.android.internal.widget.ImageFloatingTextView
+                android:id="@+id/big_text"
+                style="@style/Widget.DeviceDefault.Notification.Text"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/notification_text_margin_top"
+                android:singleLine="false"
+                android:gravity="top"
+                android:visibility="gone"
+                android:textAlignment="viewStart"
+                />
+        </com.android.internal.widget.RemeasuringLinearLayout>
+
+        <ViewStub
+            android:layout="@layout/notification_material_reply_text"
+            android:id="@+id/notification_2025_reply_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            />
+
+        <include
+            layout="@layout/notification_template_smart_reply_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:layout_marginTop="@dimen/notification_content_margin"
+            />
+
+        <include layout="@layout/notification_material_action_list" />
+    </com.android.internal.widget.RemeasuringLinearLayout>
+
+    <include layout="@layout/notification_template_right_icon" />
+</FrameLayout>
diff --git a/core/res/res/layout/notification_2025_template_expanded_call.xml b/core/res/res/layout/notification_2025_template_expanded_call.xml
new file mode 100644
index 0000000..3ff71b7
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_expanded_call.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+
+<!-- Extends FrameLayout -->
+<com.android.internal.widget.CallLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:clipChildren="false"
+    android:tag="call"
+    android:theme="@style/Theme.DeviceDefault.Notification"
+    >
+
+    <!-- CallLayout shares visual appearance with ConversationLayout, so shares layouts -->
+    <include layout="@layout/notification_2025_conversation_icon_container" />
+
+    <LinearLayout
+        android:id="@+id/notification_action_list_margin_target"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/notification_content_margin"
+        android:orientation="vertical"
+        >
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:orientation="horizontal"
+            >
+
+            <LinearLayout
+                android:id="@+id/notification_main_column"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:layout_marginStart="@dimen/conversation_content_start"
+                android:orientation="vertical"
+                android:minHeight="68dp"
+                >
+
+                <include
+                    layout="@layout/notification_template_conversation_header"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    />
+
+                <include layout="@layout/notification_template_text_multiline" />
+
+                <include
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/notification_progress_bar_height"
+                    android:layout_marginTop="@dimen/notification_progress_margin_top"
+                    layout="@layout/notification_template_progress"
+                    />
+            </LinearLayout>
+
+            <FrameLayout
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:minWidth="@dimen/notification_content_margin_end"
+                >
+
+                <include
+                    layout="@layout/notification_expand_button"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    />
+
+            </FrameLayout>
+
+        </LinearLayout>
+
+        <ViewStub
+            android:layout="@layout/notification_material_reply_text"
+            android:id="@+id/notification_material_reply_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            />
+
+        <include
+            layout="@layout/notification_template_smart_reply_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/notification_content_margin_start"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:layout_marginTop="@dimen/notification_content_margin"
+            />
+
+        <include layout="@layout/notification_material_action_list" />
+
+    </LinearLayout>
+
+</com.android.internal.widget.CallLayout>
diff --git a/core/res/res/layout/notification_2025_template_expanded_inbox.xml b/core/res/res/layout/notification_2025_template_expanded_inbox.xml
new file mode 100644
index 0000000..9fb44ccc
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_expanded_inbox.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:tag="inbox"
+    android:clipChildren="false"
+    >
+    <include layout="@layout/notification_2025_template_header" />
+    <LinearLayout
+            android:id="@+id/notification_action_list_margin_target"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_gravity="top"
+            android:layout_marginTop="@dimen/notification_content_margin_top"
+            android:clipToPadding="false"
+            android:orientation="vertical">
+
+        <LinearLayout
+            android:id="@+id/notification_main_column"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top"
+            android:paddingStart="@dimen/notification_2025_content_margin_start"
+            android:paddingEnd="@dimen/notification_content_margin_end"
+            android:layout_weight="1"
+            android:clipToPadding="false"
+            android:orientation="vertical"
+            >
+            <include layout="@layout/notification_template_part_line1"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
+            <include layout="@layout/notification_template_progress"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/notification_progress_bar_height"
+                android:layout_marginTop="@dimen/notification_progress_margin_top"
+                android:layout_marginBottom="2dp"/>
+            <TextView android:id="@+id/inbox_text0"
+                style="@style/Widget.DeviceDefault.Notification.Text"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:visibility="gone"
+                android:layout_weight="1"
+                />
+            <TextView android:id="@+id/inbox_text1"
+                style="@style/Widget.DeviceDefault.Notification.Text"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:visibility="gone"
+                android:layout_weight="1"
+                />
+            <TextView android:id="@+id/inbox_text2"
+                style="@style/Widget.DeviceDefault.Notification.Text"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:visibility="gone"
+                android:layout_weight="1"
+                />
+            <TextView android:id="@+id/inbox_text3"
+                style="@style/Widget.DeviceDefault.Notification.Text"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:visibility="gone"
+                android:layout_weight="1"
+                />
+            <TextView android:id="@+id/inbox_text4"
+                style="@style/Widget.DeviceDefault.Notification.Text"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:visibility="gone"
+                android:layout_weight="1"
+                />
+            <TextView android:id="@+id/inbox_text5"
+                style="@style/Widget.DeviceDefault.Notification.Text"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:visibility="gone"
+                android:layout_weight="1"
+                />
+            <TextView android:id="@+id/inbox_text6"
+                style="@style/Widget.DeviceDefault.Notification.Text"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:visibility="gone"
+                android:layout_weight="1"
+                />
+        </LinearLayout>
+        <ViewStub android:layout="@layout/notification_material_reply_text"
+                android:id="@+id/notification_2025_reply_container"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
+        <include layout="@layout/notification_template_smart_reply_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:layout_marginTop="@dimen/notification_content_margin" />
+        <include layout="@layout/notification_material_action_list" />
+    </LinearLayout>
+    <include layout="@layout/notification_template_right_icon" />
+</FrameLayout>
diff --git a/core/res/res/layout/notification_2025_template_expanded_media.xml b/core/res/res/layout/notification_2025_template_expanded_media.xml
new file mode 100644
index 0000000..578a0b2
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_expanded_media.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ 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
+  -->
+
+<!-- Note: This is the expanded version of the old media style notification (different from UMO). -->
+
+<!-- extends FrameLayout -->
+<com.android.internal.widget.MediaNotificationView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:tag="bigMediaNarrow"
+    >
+
+    <include layout="@layout/notification_2025_template_header" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:id="@+id/notification_media_content"
+        >
+
+        <LinearLayout
+            android:id="@+id/notification_main_column"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/notification_content_margin_top"
+            android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:orientation="vertical"
+            >
+            <include layout="@layout/notification_template_part_line1"/>
+            <include layout="@layout/notification_template_text"/>
+        </LinearLayout>
+
+        <!-- this FrameLayout's minHeight serves as a padding for the content above -->
+        <FrameLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/notification_2025_media_actions_margin_start"
+            android:minHeight="@dimen/notification_content_margin"
+            >
+
+            <!-- Nesting in FrameLayout is required to ensure that the marginStart actually applies
+                 at the start instead of always the left, given that the media_actions LinearLayout
+                 has layoutDirection="ltr". -->
+            <LinearLayout
+                android:id="@+id/media_actions"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="@dimen/media_notification_actions_padding_bottom"
+                android:gravity="top"
+                android:orientation="horizontal"
+                android:layoutDirection="ltr"
+                >
+
+                <include
+                    layout="@layout/notification_material_media_action"
+                    android:id="@+id/action0"
+                    />
+
+                <include
+                    layout="@layout/notification_material_media_action"
+                    android:id="@+id/action1"
+                    />
+
+                <include
+                    layout="@layout/notification_material_media_action"
+                    android:id="@+id/action2"
+                    />
+
+                <include
+                    layout="@layout/notification_material_media_action"
+                    android:id="@+id/action3"
+                    />
+
+                <include
+                    layout="@layout/notification_material_media_action"
+                    android:id="@+id/action4"
+                    />
+            </LinearLayout>
+
+        </FrameLayout>
+
+    </LinearLayout>
+
+    <include layout="@layout/notification_template_right_icon" />
+
+</com.android.internal.widget.MediaNotificationView>
diff --git a/core/res/res/layout/notification_2025_template_expanded_messaging.xml b/core/res/res/layout/notification_2025_template_expanded_messaging.xml
new file mode 100644
index 0000000..5b58726
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_expanded_messaging.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+
+<!-- extends FrameLayout -->
+<com.android.internal.widget.MessagingLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:clipToPadding="false"
+    android:clipChildren="false"
+    android:tag="messaging"
+    >
+
+    <include layout="@layout/notification_2025_template_header"/>
+
+    <com.android.internal.widget.RemeasuringLinearLayout
+            android:id="@+id/notification_action_list_margin_target"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top"
+            android:layout_marginTop="@dimen/notification_content_margin_top"
+            android:clipChildren="false"
+            android:orientation="vertical">
+
+        <com.android.internal.widget.RemeasuringLinearLayout
+            android:id="@+id/notification_main_column"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top"
+            android:layout_weight="1"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:orientation="vertical"
+            android:clipChildren="false"
+            >
+            <com.android.internal.widget.MessagingLinearLayout
+                android:id="@+id/notification_messaging"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:clipChildren="false"
+                android:spacing="@dimen/notification_messaging_spacing" />
+        </com.android.internal.widget.RemeasuringLinearLayout>
+
+        <include layout="@layout/notification_template_smart_reply_container"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/notification_content_margin"
+                android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+                android:layout_marginEnd="@dimen/notification_content_margin_end" />
+
+        <include layout="@layout/notification_material_action_list" />
+
+    </com.android.internal.widget.RemeasuringLinearLayout>
+
+    <include layout="@layout/notification_template_right_icon" />
+
+</com.android.internal.widget.MessagingLayout>
diff --git a/core/res/res/layout/notification_2025_template_expanded_progress.xml b/core/res/res/layout/notification_2025_template_expanded_progress.xml
new file mode 100644
index 0000000..afa4bc6
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_expanded_progress.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ 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
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:clipChildren="false"
+    android:tag="progress"
+    >
+
+    <LinearLayout
+        android:id="@+id/notification_action_list_margin_target"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/notification_content_margin"
+        android:orientation="vertical"
+        >
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_gravity="top"
+            >
+
+            <include layout="@layout/notification_2025_template_header" />
+
+            <LinearLayout
+                android:id="@+id/notification_main_column"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+                android:layout_marginEnd="@dimen/notification_content_margin_end"
+                android:layout_marginTop="@dimen/notification_content_margin_top"
+                android:orientation="vertical"
+                >
+
+                <include layout="@layout/notification_template_part_line1" />
+
+                <include layout="@layout/notification_template_text_multiline" />
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:gravity="center_vertical"
+                    android:layout_marginTop="@dimen/notification_progress_margin_top"
+                    android:orientation="horizontal">
+
+                    <com.android.internal.widget.CachingIconView
+                        android:id="@+id/notification_progress_start_icon"
+                        android:layout_width="@dimen/notification_progress_icon_size"
+                        android:layout_height="@dimen/notification_progress_icon_size"
+                        android:background="@drawable/notification_progress_icon_background"
+                        android:clipToOutline="true"
+                        android:importantForAccessibility="no"
+                        android:layout_marginEnd="@dimen/notification_progress_margin_horizontal"
+                        android:scaleType="centerCrop"
+                        android:maxDrawableWidth="@dimen/notification_progress_icon_size"
+                        android:maxDrawableHeight="@dimen/notification_progress_icon_size"
+                        />
+
+
+                    <include
+                        android:layout_width="0dp"
+                        android:layout_weight="1"
+                        android:layout_height="@dimen/notification_progress_tracker_height"
+                        layout="@layout/notification_template_notification_progress_bar"
+                        />
+
+                    <com.android.internal.widget.CachingIconView
+                        android:id="@+id/notification_progress_end_icon"
+                        android:layout_width="@dimen/notification_progress_icon_size"
+                        android:layout_height="@dimen/notification_progress_icon_size"
+                        android:background="@drawable/notification_progress_icon_background"
+                        android:clipToOutline="true"
+                        android:importantForAccessibility="no"
+                        android:scaleType="centerCrop"
+                        android:layout_marginStart="@dimen/notification_progress_margin_horizontal"
+                        android:maxDrawableWidth="@dimen/notification_progress_icon_size"
+                        android:maxDrawableHeight="@dimen/notification_progress_icon_size"
+                        />
+                </LinearLayout>
+            </LinearLayout>
+
+            <include layout="@layout/notification_template_right_icon" />
+        </FrameLayout>
+
+        <ViewStub
+            android:layout="@layout/notification_material_reply_text"
+            android:id="@+id/notification_2025_reply_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            />
+
+        <include
+            layout="@layout/notification_template_smart_reply_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:layout_marginTop="@dimen/notification_content_margin"
+            />
+
+        <include layout="@layout/notification_material_action_list" />
+    </LinearLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/notification_2025_text.xml b/core/res/res/layout/notification_2025_text.xml
new file mode 100644
index 0000000..48b1083
--- /dev/null
+++ b/core/res/res/layout/notification_2025_text.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ 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
+  -->
+<com.android.internal.widget.ImageFloatingTextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@style/Widget.DeviceDefault.Notification.Text"
+    android:id="@+id/text"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/notification_text_height"
+    android:layout_gravity="top"
+    android:layout_marginTop="@dimen/notification_text_margin_top"
+    android:fadingEdge="horizontal"
+    android:gravity="top"
+    android:maxLines="1"
+    android:textAlignment="viewStart"
+    />
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 565d584..5795936 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -13,7 +13,7 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<!-- extends FrameLayout -->
+<!-- extends RelativeLayout -->
 <NotificationHeaderView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/notification_header"
@@ -62,7 +62,7 @@
         android:layout_height="match_parent"
         android:layout_alignParentStart="true"
         android:layout_centerVertical="true"
-        android:layout_toStartOf="@id/notification_buttons_column"
+        android:layout_toStartOf="@id/expand_button"
         android:layout_alignWithParentIfMissing="true"
         android:clipChildren="false"
         android:gravity="center_vertical"
@@ -83,28 +83,17 @@
         android:focusable="false"
         />
 
-    <LinearLayout
-        android:id="@+id/notification_buttons_column"
+    <include layout="@layout/notification_expand_button"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_alignParentEnd="true"
-        android:orientation="vertical"
-        >
+        android:layout_centerVertical="true"
+        android:layout_alignParentEnd="true" />
 
-        <include layout="@layout/notification_close_button"
-            android:layout_width="@dimen/notification_close_button_size"
-            android:layout_height="@dimen/notification_close_button_size"
-            android:layout_gravity="end"
-            android:layout_marginEnd="20dp"
-            />
-
-        <include layout="@layout/notification_expand_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignParentEnd="true"
-            android:layout_centerVertical="true"
-            />
-
-    </LinearLayout>
+    <include layout="@layout/notification_close_button"
+        android:id="@+id/close_button"
+        android:layout_width="@dimen/notification_close_button_size"
+        android:layout_height="@dimen/notification_close_button_size"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentEnd="true" />
 
 </NotificationHeaderView>
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index 29f14a4..227f84b 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -157,39 +157,27 @@
             android:maxDrawableHeight="@dimen/notification_right_icon_size"
             />
 
-        <LinearLayout
-            android:id="@+id/notification_buttons_column"
+        <FrameLayout
+            android:id="@+id/expand_button_touch_container"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
-            android:layout_alignParentEnd="true"
-            android:orientation="vertical"
+            android:minWidth="@dimen/notification_content_margin_end"
             >
 
-            <include layout="@layout/notification_close_button"
-                android:layout_width="@dimen/notification_close_button_size"
-                android:layout_height="@dimen/notification_close_button_size"
-                android:layout_gravity="end"
-                android:layout_marginEnd="20dp"
+            <include layout="@layout/notification_expand_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical|end"
                 />
 
-            <FrameLayout
-                android:id="@+id/expand_button_touch_container"
-                android:layout_width="wrap_content"
-                android:layout_height="0dp"
-                android:layout_weight="1"
-                android:minWidth="@dimen/notification_content_margin_end"
-                >
-
-                <include layout="@layout/notification_expand_button"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center_vertical|end"
-                    />
-
-            </FrameLayout>
-
-        </LinearLayout>
+        </FrameLayout>
 
     </LinearLayout>
 
+    <include layout="@layout/notification_close_button"
+        android:id="@+id/close_button"
+        android:layout_width="@dimen/notification_close_button_size"
+        android:layout_height="@dimen/notification_close_button_size"
+        android:layout_gravity="top|end" />
+
 </FrameLayout>
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index 6e9d17f..5459fa8 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -15,6 +15,7 @@
   ~ limitations under the License
   -->
 
+<!-- extends FrameLayout -->
 <com.android.internal.widget.MediaNotificationView
     android:id="@+id/status_bar_latest_event_content"
     xmlns:android="http://schemas.android.com/apk/res/android"
@@ -191,4 +192,11 @@
         </FrameLayout>
 
     </LinearLayout>
+
+    <include layout="@layout/notification_close_button"
+        android:id="@+id/close_button"
+        android:layout_width="@dimen/notification_close_button_size"
+        android:layout_height="@dimen/notification_close_button_size"
+        android:layout_gravity="top|end" />
+
 </com.android.internal.widget.MediaNotificationView>
diff --git a/core/res/res/layout/notification_template_material_messaging.xml b/core/res/res/layout/notification_template_material_messaging.xml
index 1eae41d..2b3b7d8 100644
--- a/core/res/res/layout/notification_template_material_messaging.xml
+++ b/core/res/res/layout/notification_template_material_messaging.xml
@@ -195,6 +195,12 @@
 
             </LinearLayout>
 
+            <include layout="@layout/notification_close_button"
+                android:id="@+id/close_button"
+                android:layout_width="@dimen/notification_close_button_size"
+                android:layout_height="@dimen/notification_close_button_size"
+                android:layout_gravity="top|end" />
+
         </com.android.internal.widget.NotificationMaxHeightFrameLayout>
 
     <LinearLayout
diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml
index bed80ed..7a2fb0b 100644
--- a/core/res/res/layout/preference_list_content.xml
+++ b/core/res/res/layout/preference_list_content.xml
@@ -20,6 +20,7 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
+    android:fitsSystemWindows="true"
     android:layout_height="match_parent"
     android:layout_width="match_parent">
 
diff --git a/core/res/res/layout/preference_list_content_material.xml b/core/res/res/layout/preference_list_content_material.xml
index 37b4119..23c8250 100644
--- a/core/res/res/layout/preference_list_content_material.xml
+++ b/core/res/res/layout/preference_list_content_material.xml
@@ -20,6 +20,7 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
+    android:fitsSystemWindows="true"
     android:layout_height="match_parent"
     android:layout_width="match_parent">
 
diff --git a/core/res/res/layout/preference_list_content_single.xml b/core/res/res/layout/preference_list_content_single.xml
index 726ce78..4f072da 100644
--- a/core/res/res/layout/preference_list_content_single.xml
+++ b/core/res/res/layout/preference_list_content_single.xml
@@ -19,6 +19,7 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
+    android:fitsSystemWindows="true"
     android:layout_height="match_parent"
     android:layout_width="match_parent">
 
diff --git a/core/res/res/layout/preference_list_fragment.xml b/core/res/res/layout/preference_list_fragment.xml
index c43975e..44a5df9 100644
--- a/core/res/res/layout/preference_list_fragment.xml
+++ b/core/res/res/layout/preference_list_fragment.xml
@@ -19,6 +19,7 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
+    android:fitsSystemWindows="true"
     android:layout_height="match_parent"
     android:layout_width="match_parent"
     android:background="@android:color/transparent"
diff --git a/core/res/res/layout/preference_list_fragment_material.xml b/core/res/res/layout/preference_list_fragment_material.xml
index db2fe7d..4df7602 100644
--- a/core/res/res/layout/preference_list_fragment_material.xml
+++ b/core/res/res/layout/preference_list_fragment_material.xml
@@ -19,6 +19,7 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
+    android:fitsSystemWindows="true"
     android:layout_height="match_parent"
     android:layout_width="match_parent"
     android:background="@android:color/transparent"
diff --git a/core/res/res/layout/side_fps_toast.xml b/core/res/res/layout/side_fps_toast.xml
index 78299ab..7bb6fcf 100644
--- a/core/res/res/layout/side_fps_toast.xml
+++ b/core/res/res/layout/side_fps_toast.xml
@@ -25,7 +25,7 @@
         android:layout_height="wrap_content"
         android:layout_width="0dp"
         android:layout_weight="6"
-        android:paddingBottom="10dp"
+        android:paddingBottom="16dp"
         android:text="@string/fp_power_button_enrollment_title"
         android:textColor="@color/side_fps_text_color"
         android:paddingLeft="20dp"/>
@@ -37,7 +37,7 @@
         android:layout_height="wrap_content"
         android:layout_width="0dp"
         android:layout_weight="3"
-        android:paddingBottom="10dp"
+        android:paddingBottom="16dp"
         android:text="@string/fp_power_button_enrollment_button_text"
         style="?android:attr/buttonBarNegativeButtonStyle"
         android:textColor="@color/side_fps_button_color"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index a4499ef..b0545eb 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>-<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> tot <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Enige kalender"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> demp sekere klanke"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Daar is \'n interne probleem met jou toestel en dit sal dalk onstabiel wees totdat jy \'n fabriekterugstelling doen."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 225f04d..e56f79a 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">"፣ "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"ከ<xliff:g id="START">%1$s</xliff:g> እስከ <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"ማንኛውም ቀን መቁጠሪያ"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> አንዳንድ ድምጾችን እየዘጋ ነው"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"መሣሪያዎ ላይ የውስጣዊ ችግር አለ፣ የፋብሪካ ውሂብ ዳግም እስኪያስጀምሩት ድረስ ላይረጋጋ ይችላል።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 484d220..ebffb4d 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1951,6 +1951,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">"، "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"من <xliff:g id="START">%1$s</xliff:g> إلى <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"من <xliff:g id="START">%1$s</xliff:g> إلى <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"أي تقويم"</string>
     <string name="muted_by" msgid="91464083490094950">"يعمل <xliff:g id="THIRD_PARTY">%1$s</xliff:g> على كتم بعض الأصوات."</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"حدثت مشكلة داخلية في جهازك، وقد لا يستقر وضعه حتى إجراء إعادة الضبط على الإعدادات الأصلية."</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index fdddc70..f80352e 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g>ৰ পৰা <xliff:g id="END">%2$s</xliff:g>লৈ"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"যিকোনো কেলেণ্ডাৰ"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>এ কিছুমান ধ্বনি মিউট কৰি আছে"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"আপোনাৰ ডিভাইচত এটা আভ্যন্তৰীণ সমস্যা আছে আৰু আপুনি ফেক্টৰী ডেটা ৰিছেট নকৰালৈকে ই সুস্থিৰভাৱে কাম নকৰিব পাৰে।"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 003c0db..57e2ddd4 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"İstənilən təqvim"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> bəzi səsləri səssiz rejimə salır"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Cihazınızın daxili problemi var və istehsalçı sıfırlanması olmayana qədər qeyri-stabil ola bilər."</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 5a848ba..26ded97 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1948,6 +1948,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Bilo koji kalendar"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> isključuje neke zvuke"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Došlo je do internog problema u vezi sa uređajem i možda će biti nestabilan dok ne obavite resetovanje na fabrička podešavanja."</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index ce98a5f..4d85437 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1949,6 +1949,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>-<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Любы каляндар"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> выключае некаторыя гукі"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"На вашай прыладзе ўзнікла ўнутраная праблема, і яна можа працаваць нестабільна, пакуль вы не зробіце скід да заводскіх налад."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index aad5d48..226447a 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"От <xliff:g id="START">%1$s</xliff:g> до <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Всички календари"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> заглушава някои звуци"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Възникна вътрешен проблем с устройството ви. То може да е нестабилно, докато не възстановите фабричните настройки."</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index d52f6e9..521b092 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> থেকে <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"যেকোনও ক্যালেন্ডার"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> কিছু সাউন্ডকে মিউট করে দিচ্ছে"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"আপনার ডিভাইসে একটি অভ্যন্তরীন সমস্যা হয়েছে, এবং আপনি যতক্ষণ না পর্যন্ত এটিকে ফ্যাক্টরি ডেটা রিসেট করছেন ততক্ষণ এটি ঠিকভাবে কাজ নাও করতে পারে৷"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index b74b139..e22d838 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1948,6 +1948,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Bilo koji kalendar"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> isključuje neke zvukove"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Postoji problem u vašem uređaju i može biti nestabilan dok ga ne vratite na fabričke postavke."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 7500122..6b3c9bf 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1948,6 +1948,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>-<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"De <xliff:g id="START">%1$s</xliff:g> a <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Qualsevol calendari"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> està silenciant alguns sons"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"S\'ha produït un error intern al dispositiu i és possible que funcioni de manera inestable fins que restableixis les dades de fàbrica."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 277d359..b0760fe 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1949,6 +1949,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"V libovolném kalendáři"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> vypíná určité zvuky"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"V zařízení došlo k internímu problému. Dokud neprovedete obnovení továrních dat, může být nestabilní."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 9db6076..f4fa796 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>-<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> til <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Alle kalendere"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> slår nogle lyde fra"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Der er et internt problem med enheden, og den vil muligvis være ustabil, indtil du gendanner fabriksdataene."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 9561b3f..5bf7933 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> bis <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Alle Kalender"</string>
     <string name="muted_by" msgid="91464083490094950">"Einige Töne werden von <xliff:g id="THIRD_PARTY">%1$s</xliff:g> stummgeschaltet"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Es liegt ein internes Problem mit deinem Gerät vor. Möglicherweise verhält es sich instabil, bis du es auf die Werkseinstellungen zurücksetzt."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 551fe70..8289ff7 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> έως <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Οποιοδήποτε ημερολόγιο"</string>
     <string name="muted_by" msgid="91464083490094950">"Το τρίτο μέρος <xliff:g id="THIRD_PARTY">%1$s</xliff:g> θέτει ορισμένους ήχους σε σίγαση"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Υπάρχει ένα εσωτερικό πρόβλημα με τη συσκευή σας και ενδέχεται να είναι ασταθής μέχρι την επαναφορά των εργοστασιακών ρυθμίσεων."</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 5cedb1f..0390acf 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> to <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Any calendar"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> is muting some sounds"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"There\'s an internal problem with your device, and it may be unstable until you factory data reset."</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index b09a79a..5373b1e 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> to <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Any calendar"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> is muting some sounds"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"There\'s an internal problem with your device, and it may be unstable until you factory data reset."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 4e728ff0..d4bdad0 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> to <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Any calendar"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> is muting some sounds"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"There\'s an internal problem with your device, and it may be unstable until you factory data reset."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 578e479..3eda31b 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> to <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Any calendar"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> is muting some sounds"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"There\'s an internal problem with your device, and it may be unstable until you factory data reset."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index da3c4c4..de3945a 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1948,6 +1948,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"De <xliff:g id="START">%1$s</xliff:g> a <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Cualquier calendario"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> silencia algunos sonidos"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Existe un problema interno con el dispositivo, de modo que el dispositivo puede estar inestable hasta que restablezcas la configuración de fábrica."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 37bf70e..e9ac320 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1948,6 +1948,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>-<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"De <xliff:g id="START">%1$s</xliff:g> a <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Cualquier calendario"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> silencia algunos sonidos"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Se ha producido un problema interno en el dispositivo y es posible que este no sea estable hasta que restablezcas el estado de fábrica."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 0d79e8a..69a3dd3 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> kuni <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Mis tahes kalender"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> vaigistab teatud helid"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Seadmes ilmnes sisemine probleem ja seade võib olla ebastabiilne seni, kuni lähtestate seadme tehase andmetele."</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index b96f9eb..e4f4bbd 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>-<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g>-<xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Edozein egutegi"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> soinu batzuk isilarazten ari da"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Barneko arazo bat dago zure gailuan eta agian ezegonkor egongo da jatorrizko datuak berrezartzen dituzun arte."</string>
@@ -2438,7 +2440,7 @@
     <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Satelite bidezko SOS komunikazioa ez da bateragarria"</string>
     <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Satelite bidezko SOS komunikazioa ez da bateragarria gailu honekin"</string>
     <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Satelite bidezko SOS komunikazioa ez dago konfiguratuta"</string>
-    <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Ziurtatu Internetera konektatuta zaudela eta saiatu konfiguratzen berriro"</string>
+    <string name="satellite_sos_not_provisioned_notification_summary" msgid="3127320958911180629">"Ziurtatu Internetera konektatuta zaudela eta saiatu berriro konfiguratzen"</string>
     <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Satelite bidezko SOS komunikazioa ez dago erabilgarri"</string>
     <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Satelite bidezko SOS komunikazioa ez dago erabilgarri herrialde edo lurralde honetan"</string>
     <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Satelite bidezko SOS komunikazioa ez dago konfiguratuta"</string>
@@ -2450,7 +2452,7 @@
     <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Satelite bidezko mezularitza ez da bateragarria"</string>
     <string name="satellite_messaging_not_supported_notification_summary" msgid="61629858627638545">"Satelite bidezko mezularitza ez da bateragarria gailu honekin"</string>
     <string name="satellite_messaging_not_provisioned_notification_title" msgid="961909101918169727">"Satelite bidezko mezularitza ez dago konfiguratuta"</string>
-    <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Ziurtatu Internetera konektatuta zaudela eta saiatu konfiguratzen berriro"</string>
+    <string name="satellite_messaging_not_provisioned_notification_summary" msgid="1060961852174442155">"Ziurtatu Internetera konektatuta zaudela eta saiatu berriro konfiguratzen"</string>
     <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Satelite bidezko mezularitza ez dago erabilgarri"</string>
     <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Satelite bidezko mezularitza ez dago erabilgarri herrialde edo lurralde honetan"</string>
     <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Satelite bidezko mezularitza ez dago konfiguratuta"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 7627ff3..b87fe90 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">"، "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"‫<xliff:g id="START">%1$s</xliff:g> تا <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"هر تقویمی"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> درحال قطع کردن بعضی از صداهاست"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"دستگاهتان یک مشکل داخلی دارد، و ممکن است تا زمانی که بازنشانی داده‌های کارخانه انجام نگیرد، بی‌ثبات بماند."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 78fb2a0..867d32f 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Kaikki kalenterit"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> mykistää joitakin ääniä"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Laitteellasi on sisäinen ongelma, joka aiheuttaa epävakautta. Voit korjata tilanteen palauttamalla tehdasasetukset."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 163d70d..3683248 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1948,6 +1948,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"De <xliff:g id="START">%1$s</xliff:g> à <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"N\'importe quel agenda"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> désactive certains sons"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Un problème interne est survenu avec votre appareil. Il se peut qu\'il soit instable jusqu\'à ce que vous le réinitialisiez à ses paramètres par défaut."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 75b8e31..9f752db 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1948,6 +1948,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"De <xliff:g id="START">%1$s</xliff:g> à <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Tous les agendas"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> coupe certains sons"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Un problème interne lié à votre appareil est survenu. Ce dernier risque d\'être instable jusqu\'à ce que vous rétablissiez la configuration d\'usine."</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 70a7ec9..766fdbf 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"De <xliff:g id="START">%1$s</xliff:g> a <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Calquera calendario"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> está silenciando algúns sons"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Produciuse un erro interno no teu dispositivo e quizais funcione de maneira inestable ata o restablecemento dos datos de fábrica."</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 1535e4f..ab32a7a 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g>થી <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"કોઈપણ કૅલેન્ડર"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> અમુક અવાજોને મ્યૂટ કરે છે"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"તમારા ઉપકરણમાં આંતરિક સમસ્યા છે અને જ્યાં સુધી તમે ફેક્ટરી ડેટા ફરીથી સેટ કરશો નહીં ત્યાં સુધી તે અસ્થિર રહી શકે છે."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index c5825fe..3a07058 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> से <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"किसी भी कैलेंडर के इवेंट के लिए"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> कुछ आवाज़ें म्‍यूट कर रहा है"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"आपके डिवाइस में कोई अंदरूनी समस्या है और यह तब तक ठीक नहीं होगी जब तक आप फ़ैक्‍टरी डेटा रीसेट नहीं करते."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 954f4cb..010f099 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1948,6 +1948,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Bilo koji kalendar"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> isključuje neke zvukove"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Na vašem uređaju postoji interni problem i možda neće biti stabilan dok ga ne vratite na tvorničko stanje."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 58a5cbd..baace73 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Bármilyen naptár"</string>
     <string name="muted_by" msgid="91464083490094950">"A(z) <xliff:g id="THIRD_PARTY">%1$s</xliff:g> lenémít néhány hangot"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Belső probléma van az eszközzel, és instabil lehet, amíg vissza nem állítja a gyári adatokat."</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index f457c42d..e8c6280c 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Ցանկացած օրացույց"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>-ն անջատում է որոշ ձայներ"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Սարքում ներքին խնդիր է առաջացել և այն կարող է կրկնվել, մինչև չվերականգնեք գործարանային կարգավորումները:"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 88764c4..0384ce5 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> hingga <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Kalender mana saja"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> mematikan beberapa suara"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Ada masalah dengan perangkat. Hal ini mungkin membuat perangkat jadi tidak stabil dan perlu dikembalikan ke setelan pabrik."</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 8e92ed1..b63ea1c 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> til <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Öll dagatöl"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> þaggar í einhverjum hljóðum"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Innra vandamál kom upp í tækinu og það kann að vera óstöðugt þangað til þú núllstillir það."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 49f1f21..43cee8a 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -169,7 +169,7 @@
     <string name="scNullCipherIssueActionGotIt" msgid="8747796640866585787">"Ok"</string>
     <string name="fcComplete" msgid="1080909484660507044">"Codice funzione completo."</string>
     <string name="fcError" msgid="5325116502080221346">"Problema di connessione o codice funzione non valido."</string>
-    <string name="httpErrorOk" msgid="6206751415788256357">"OK"</string>
+    <string name="httpErrorOk" msgid="6206751415788256357">"Ok"</string>
     <string name="httpError" msgid="3406003584150566720">"Si è verificato un errore di rete."</string>
     <string name="httpErrorLookup" msgid="3099834738227549349">"Impossibile trovare l\'URL."</string>
     <string name="httpErrorUnsupportedAuthScheme" msgid="3976195595501606787">"Schema di autenticazione del sito non supportato."</string>
@@ -1167,7 +1167,7 @@
     <string name="VideoView_error_title" msgid="5750686717225068016">"Problemi video"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Questo video non è valido per lo streaming su questo dispositivo."</string>
     <string name="VideoView_error_text_unknown" msgid="7658683339707607138">"Impossibile riprodurre il video."</string>
-    <string name="VideoView_error_button" msgid="5138809446603764272">"OK"</string>
+    <string name="VideoView_error_button" msgid="5138809446603764272">"Ok"</string>
     <string name="relative_time" msgid="8572030016028033243">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="noon" msgid="8365974533050605886">"mezzogiorno"</string>
     <string name="Noon" msgid="6902418443846838189">"Mezzogiorno"</string>
@@ -1206,7 +1206,7 @@
     <string name="app_running_notification_text" msgid="5120815883400228566">"Tocca per ulteriori informazioni o per interrompere l\'app."</string>
     <string name="ok" msgid="2646370155170753815">"Ok"</string>
     <string name="cancel" msgid="6908697720451760115">"Annulla"</string>
-    <string name="yes" msgid="9069828999585032361">"OK"</string>
+    <string name="yes" msgid="9069828999585032361">"Ok"</string>
     <string name="no" msgid="5122037903299899715">"Annulla"</string>
     <string name="dialog_alert_title" msgid="651856561974090712">"Attenzione"</string>
     <string name="loading" msgid="3138021523725055037">"Caricamento…"</string>
@@ -1265,7 +1265,7 @@
     <string name="anr_activity_process" msgid="3477362583767128667">"L\'app <xliff:g id="ACTIVITY">%1$s</xliff:g> non risponde"</string>
     <string name="anr_application_process" msgid="4978772139461676184">"L\'app <xliff:g id="APPLICATION">%1$s</xliff:g> non risponde"</string>
     <string name="anr_process" msgid="1664277165911816067">"Il processo <xliff:g id="PROCESS">%1$s</xliff:g> non risponde"</string>
-    <string name="force_close" msgid="9035203496368973803">"OK"</string>
+    <string name="force_close" msgid="9035203496368973803">"Ok"</string>
     <string name="report" msgid="2149194372340349521">"Segnala"</string>
     <string name="wait" msgid="7765985809494033348">"Attendi"</string>
     <string name="webpage_unresponsive" msgid="7850879412195273433">"La pagina non risponde più.\n\nVuoi chiuderla?"</string>
@@ -1395,7 +1395,7 @@
     <string name="perms_description_app" msgid="2747752389870161996">"Fornito da <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="no_permissions" msgid="5729199278862516390">"Nessuna autorizzazione richiesta"</string>
     <string name="perm_costs_money" msgid="749054595022779685">"potrebbe comportare dei costi"</string>
-    <string name="dlg_ok" msgid="5103447663504839312">"OK"</string>
+    <string name="dlg_ok" msgid="5103447663504839312">"Ok"</string>
     <string name="usb_charging_notification_title" msgid="1674124518282666955">"Dispositivo in carica tramite USB"</string>
     <string name="usb_supplying_notification_title" msgid="5378546632408101811">"Dispositivo collegato in carica tramite USB"</string>
     <string name="usb_mtp_notification_title" msgid="1065989144124499810">"Trasferimento file tramite USB attivato"</string>
@@ -1892,7 +1892,7 @@
     <string name="restr_pin_try_later" msgid="5897719962541636727">"Riprova più tardi"</string>
     <string name="immersive_cling_title" msgid="2307034298721541791">"Visualizzazione a schermo intero"</string>
     <string name="immersive_cling_description" msgid="2896205051090870978">"Per uscire, scorri verso il basso dalla parte superiore dello schermo"</string>
-    <string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
+    <string name="immersive_cling_positive" msgid="7047498036346489883">"Ok"</string>
     <string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Ruota per migliorare l\'anteprima"</string>
     <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Apri <xliff:g id="NAME">%s</xliff:g> a schermo intero per migliorare la visualizzazione"</string>
     <string name="done_label" msgid="7283767013231718521">"Fine"</string>
@@ -1914,7 +1914,7 @@
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installato dall\'amministratore.\nVai alle impostazioni per visualizzare le autorizzazioni concesse"</string>
     <string name="package_updated_device_owner" msgid="7560272363805506941">"Aggiornato dall\'amministratore"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminato dall\'amministratore"</string>
-    <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
+    <string name="confirm_battery_saver" msgid="5247976246208245754">"Ok"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Il risparmio energetico attiva il tema scuro e limita o disattiva l\'attività in background, nonché alcuni effetti visivi, funzionalità e connessioni di rete."</string>
     <string name="battery_saver_description" msgid="8518809702138617167">"Il risparmio energetico attiva il tema scuro e limita o disattiva l\'attività in background, nonché alcuni effetti visivi, funzionalità e connessioni di rete."</string>
     <string name="data_saver_description" msgid="4995164271550590517">"Per contribuire a ridurre l\'utilizzo dei dati, la funzionalità Risparmio dati impedisce ad alcune app di inviare o ricevere dati in background. Un\'app in uso può accedere ai dati, ma potrebbe farlo con meno frequenza. Per esempio, è possibile che le immagini non vengano visualizzate finché non le tocchi."</string>
@@ -1948,6 +1948,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"Da <xliff:g id="START">%1$s</xliff:g> a <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Qualsiasi calendario"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> sta disattivando alcuni suoni"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Si è verificato un problema interno con il dispositivo, che potrebbe essere instabile fino al ripristino dei dati di fabbrica."</string>
@@ -2150,7 +2152,7 @@
     <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Questa notifica è stata posizionata più in basso. Tocca per dare un feedback."</string>
     <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notifiche avanzate"</string>
     <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Ora le risposte e le azioni suggerite vengono fornite dalle notifiche avanzate. Le notifiche adattive Android non sono più supportate."</string>
-    <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+    <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Ok"</string>
     <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Disattiva"</string>
     <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Scopri di più"</string>
     <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Le notifiche adattive Android sono state sostituite dalle notifiche avanzate in Android 12. Questa funzionalità mostra risposte e azioni suggerite e organizza le tue notifiche.\n\nLe notifiche avanzate possono accedere ai contenuti di una notifica, incluse le informazioni personali, come i nomi dei contatti e i messaggi. Questa funzionalità può anche ignorare le notifiche o rispondervi, ad esempio accettando le telefonate, e controllare la modalità Non disturbare."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 0e8f472..0b70b94 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1948,6 +1948,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"‫<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"‫<xliff:g id="START">%1$s</xliff:g> עד <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"כל יומן"</string>
     <string name="muted_by" msgid="91464083490094950">"חלק מהצלילים מושתקים על ידי <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"קיימת בעיה פנימית במכשיר שלך, וייתכן שהוא לא יתפקד כראוי עד שיבוצע איפוס לנתוני היצרן."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 6eabd4a..b6a2b24 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">"、 "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>~<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g>~<xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"すべてのカレンダー"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> により一部の音はミュートに設定"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"デバイスで内部的な問題が発生しました。データが初期化されるまで不安定になる可能性があります。"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 4ffa312..1554714 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g>-<xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"ნებისმიერი კალენდარი"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ზოგიერთ ხმას ადუმებს"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"ფიქსირდება თქვენი მ ოწყობილობის შიდა პრობლემა და შეიძლება არასტაბილური იყოს, სანამ ქარხნულ მონაცემების არ განაახლებთ."</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 6355d86..f2a6b08 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Кез келген күнтізбе"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> кейбір дыбыстарды өшіруде"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"There\'s an internal problem with your device, and it may be unstable until you factory data reset."</string>
@@ -2442,9 +2444,9 @@
     <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"Satellite SOS функциясы қолжетімді емес"</string>
     <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"Satellite SOS функциясы бұл елде немесе аймақта қолжетімді емес."</string>
     <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"Satellite SOS функциясы реттелмеген"</string>
-    <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Жерсерік арқылы хабар алмасу үшін, Google Messages сіздің әдепкі хабар алмасу қолданбаңыз болуы керек."</string>
+    <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"Жерсерік арқылы хабар алмасу үшін Google Messages сіздің әдепкі хабар алмасу қолданбаңыз болуы керек."</string>
     <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"Satellite SOS функциясы қолжетімді емес"</string>
-    <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Satellite SOS функциясының бұл елде немесе аймақта қолжетімді екенін тексеру үшін, локация параметрлерін қосыңыз."</string>
+    <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"Satellite SOS функциясының бұл елде немесе аймақта қолжетімді екенін тексеру үшін локация параметрлерін қосыңыз."</string>
     <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"Жерсерік арқылы хабар алмасу функциясы қолжетімді"</string>
     <string name="satellite_messaging_available_notification_summary" msgid="7573949038500243670">"Мобильдік немесе Wi-Fi желісі жоқ болған жағдайда, жерсерік арқылы хабар алмаса аласыз. Google Messages сіздің әдепкі хабар алмасу қолданбаңыз болуы керек."</string>
     <string name="satellite_messaging_not_supported_notification_title" msgid="8202139632766878610">"Жерсерік арқылы хабар алмасу функциясына қолдау көрсетілмейді"</string>
@@ -2454,9 +2456,9 @@
     <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"Жерсерік арқылы хабар алмасу функциясы қолжетімді емес"</string>
     <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"Жерсерік арқылы хабар алмасу функциясы бұл елде немесе аймақта қолжетімді емес."</string>
     <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"Жерсерік арқылы хабар алмасу функциясы реттелмеген"</string>
-    <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Жерсерік арқылы хабар алмасу үшін, Google Messages сіздің әдепкі хабар алмасу қолданбаңыз болуы керек."</string>
+    <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"Жерсерік арқылы хабар алмасу үшін Google Messages сіздің әдепкі хабар алмасу қолданбаңыз болуы керек."</string>
     <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"Жерсерік арқылы хабар алмасу функциясы қолжетімді емес"</string>
-    <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Жерсерік арқылы хабар алмасу функциясының бұл елде немесе аймақта қолжетімді екенін тексеру үшін, локация параметрлерін қосыңыз."</string>
+    <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"Жерсерік арқылы хабар алмасу функциясының бұл елде немесе аймақта қолжетімді екенін тексеру үшін локация параметрлерін қосыңыз."</string>
     <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Саусақ ізімен ашу функциясын қайта реттеу"</string>
     <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> бұдан былай танылмайды."</string>
     <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> және <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> бұдан былай танылмайды."</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 4163be4..287677e 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> ដល់ <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"ប្រតិទិនណាមួយ"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> កំពុង​បិទសំឡេង​មួយចំនួន"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"មានបញ្ហាខាងក្នុងឧបករណ៍របស់អ្នក ហើយវាអ្នកមិនមានស្ថេរភាព រហូតទាល់តែអ្នកកំណត់ដូចដើមវិញទាំងស្រុង។"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 234ba66..de44b87 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1387,7 +1387,7 @@
     <string name="carrier_app_notification_title" msgid="5815477368072060250">"ಹೊಸ ಸಿಮ್ ಸೇರಿಸಲಾಗಿದೆ"</string>
     <string name="carrier_app_notification_text" msgid="6567057546341958637">"ಇದನ್ನು ಸ್ಥಾಪಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="time_picker_dialog_title" msgid="9053376764985220821">"ಸಮಯವನ್ನು ಹೊಂದಿಸಿ"</string>
-    <string name="date_picker_dialog_title" msgid="5030520449243071926">"ದಿನಾಂಕವನ್ನು ಹೊಂದಿಸಿ"</string>
+    <string name="date_picker_dialog_title" msgid="5030520449243071926">"ದಿನಾಂಕವನ್ನು ಸೆಟ್ ಮಾಡಿ"</string>
     <string name="date_time_set" msgid="4603445265164486816">"ಹೊಂದಿಸು"</string>
     <string name="date_time_done" msgid="8363155889402873463">"ಆಯಿತು"</string>
     <string name="perms_new_perm_prefix" msgid="6984556020395757087"><font size="12" fgcolor="#ff33b5e5">"ಹೊಸ: "</font></string>
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> ನಿಂದ <xliff:g id="END">%2$s</xliff:g> ವರೆಗೆ"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"ಯಾವುದೇ ಕ್ಯಾಲೆಂಡರ್"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ಧ್ವನಿ ಮ್ಯೂಟ್ ಮಾಡುತ್ತಿದ್ದಾರೆ"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಆಂತರಿಕ ಸಮಸ್ಯೆಯಿದೆ ಹಾಗೂ ನೀವು ಫ್ಯಾಕ್ಟರಿ ಡೇಟಾವನ್ನು ರೀಸೆಟ್ ಮಾಡುವವರೆಗೂ ಅದು ಅಸ್ಥಿರವಾಗಬಹುದು."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 59af8fb..7116c6e 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>~<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g>~<xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"모든 캘린더"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>(이)가 일부 소리를 음소거함"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"사용 중인 기기 내부에 문제가 발생했습니다. 초기화할 때까지 불안정할 수 있습니다."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index cbb0a13..63b5b39 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>, <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Бардык жылнаамалар"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> айрым үндөрдү өчүрүүдө"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Түзмөгүңүздө ички көйгөй бар жана ал баштапкы абалга кайтарылмайынча туруктуу иштебей коюшу мүмкүн."</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 5af4a84..8a4da89 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> ຫາ <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"ປະ​ຕິ​ທິນ​ໃດ​ກໍໄດ້"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ປິດສຽງບາງຢ່າງໄວ້"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"ມີ​ບັນ​ຫາ​ພາຍ​ໃນ​ກັບ​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ, ແລະ​ມັນ​ອາດ​ຈະ​ບໍ່​ສະ​ຖຽນ​ຈົນ​ກວ່າ​ທ່ານ​ຕັ້ງ​ເປັນ​ຂໍ້​ມູນ​ໂຮງ​ງານ​ຄືນ​ແລ້ວ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index cb7cc89..e6cc845 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1949,6 +1949,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Bet kuris kalendorius"</string>
     <string name="muted_by" msgid="91464083490094950">"„<xliff:g id="THIRD_PARTY">%1$s</xliff:g>“ nutildo kai kuriuos garsus"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Iškilo vidinė su jūsų įrenginiu susijusi problema, todėl įrenginys gali veikti nestabiliai, kol neatkursite gamyklinių duomenų."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index b72fb07..515aaae 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1948,6 +1948,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"no <xliff:g id="START">%1$s</xliff:g> līdz <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Jebkurš kalendārs"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> izslēdz noteiktas skaņas"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Jūsu ierīcē ir radusies iekšēja problēma, un ierīce var darboties nestabili. Lai to labotu, veiciet rūpnīcas datu atiestatīšanu."</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 0b0e3ef..1a13752 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> до <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Кој било календар"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> исклучи некои звуци"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Настана внатрешен проблем со уредот и може да биде нестабилен сè додека не ресетирате на фабричките податоци."</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index fe5974b..3291e22 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> മുതൽ <xliff:g id="END">%2$s</xliff:g> വരെ"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"എല്ലാ കലണ്ടറിലും"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ചില ശബ്‌ദങ്ങൾ മ്യൂട്ട് ചെയ്യുന്നു"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"നിങ്ങളുടെ ഉപകരണത്തിൽ ഒരു ആന്തരിക പ്രശ്‌നമുണ്ട്, ഫാക്‌ടറി വിവര പുനഃസജ്ജീകരണം ചെയ്യുന്നതുവരെ ഇതു അസ്ഥിരമായിരിക്കാനിടയുണ്ട്."</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 376a033..f608c23b 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g>-с <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Дурын календарь"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> зарим дууны дууг хааж байна"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Таны төхөөрөмжид дотоод алдаа байна.Та төхөөрөмжөө үйлдвэрээс гарсан төлөвт шилжүүлэх хүртэл таны төхөөрөмж чинь тогтворгүй байж болох юм."</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index e640f72..b9c955e 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> ते <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"कोणतेही कॅलेंडर"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> काही ध्‍वनी म्‍यूट करत आहे"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"आपल्‍या डिव्‍हाइसमध्‍ये अंतर्गत समस्‍या आहे आणि तुमचा फॅक्‍टरी डेटा रीसेट होईपर्यंत ती अस्‍थिर असू शकते."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 3946ac1..01e070f 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> hingga <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Sebarang kalendar"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> meredamkan sesetengah bunyi"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Terdapat masalah dalaman dengan peranti anda. Peranti mungkin tidak stabil sehingga anda membuat tetapan semula data kilang."</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index fc00725..e957ea2 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">"၊ "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> မှ <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"မည်သည့်ပြက္ခဒိန်မဆို"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> သည် အချို့အသံကို ပိတ်နေသည်"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"သင့်ကိရိယာအတွင်းပိုင်းတွင် ပြဿနာရှိနေပြီး၊ မူလစက်ရုံထုတ်အခြေအနေအဖြစ် ပြန်လည်ရယူနိုင်သည်အထိ အခြေအနေမတည်ငြိမ်နိုင်ပါ။"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index c1095d3..b2eaf95 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> til <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Hvilken som helst kalender"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> slår av noen lyder"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Det har oppstått et internt problem på enheten din, og den kan være ustabil til du tilbakestiller den til fabrikkdata."</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index beda131..2eee141 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1105,7 +1105,7 @@
     <string name="permlab_addVoicemail" msgid="4770245808840814471">"भ्वाइसमेल थप गर्नुहोस्"</string>
     <string name="permdesc_addVoicemail" msgid="5470312139820074324">"तपाईँको भ्वाइसमेल इनबक्समा सन्देश थप्नको लागि एपलाई अनुमति दिन्छ।"</string>
     <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ले तपाईंको क्लिपबोर्डमा रहेको जानकारी पेस्ट गरेको छ"</string>
-    <string name="more_item_label" msgid="7419249600215749115">"बढी"</string>
+    <string name="more_item_label" msgid="7419249600215749115">"थप"</string>
     <string name="prepend_shortcut_label" msgid="1743716737502867951">"मेनु+"</string>
     <string name="menu_meta_shortcut_label" msgid="1623390163674762478">"Meta+"</string>
     <string name="menu_ctrl_shortcut_label" msgid="131911133027196485">"Ctrl+"</string>
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> देखि <xliff:g id="END">%2$s</xliff:g> सम्म"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"कुनै पनि पात्रो"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ले केही ध्वनिहरू म्युट गर्दै छ"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"तपाईंको यन्त्रसँग आन्तरिक समस्या छ, र तपाईंले फ्याक्ट्री डाटा रिसेट नगर्दासम्म यो अस्थिर रहन्छ।"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 48c8be1..5a45223 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> tot <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Elke agenda"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> zet sommige geluiden uit"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Er is een intern probleem met je apparaat. Het apparaat kan instabiel zijn totdat u het apparaat terugzet naar de fabrieksinstellingen."</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index a99afa5..afcb3d8 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g>ରୁ <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"ଯେକୌଣସି କ୍ୟାଲେଣ୍ଡର୍‌"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> କିଛି ସାଉଣ୍ଡକୁ ମ୍ୟୁଟ୍ କରୁଛି"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"ଆପଣଙ୍କ ଡିଭାଇସ୍‍ରେ ଏକ ସମସ୍ୟା ରହିଛି ଏବଂ ଆପଣ ଫ୍ୟାକ୍ଟୋରୀ ଡାଟା ରିସେଟ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଅସ୍ଥିର ରହିପାରେ।"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index b4630174..8422b93 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> ਤੋਂ <xliff:g id="END">%2$s</xliff:g> ਤੱਕ"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"ਕੋਈ ਵੀ ਕੈਲੰਡਰ"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ਕੁਝ ਧੁਨੀਆਂ ਨੂੰ ਮਿਊਟ ਕਰ ਰਹੀ ਹੈ"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਨਾਲ ਇੱਕ ਅੰਦਰੂਨੀ ਸਮੱਸਿਆ ਹੈ ਅਤੇ ਇਹ ਅਸਥਿਰ ਹੋ ਸਕਦੀ ਹੈ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਫੈਕਟਰੀ ਡਾਟਾ ਰੀਸੈੱਟ ਨਹੀਂ ਕਰਦੇ।"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 4f34fc5..4eccff5 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1949,6 +1949,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"Od <xliff:g id="START">%1$s</xliff:g> do <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Dowolny kalendarz"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> wycisza niektóre dźwięki"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"W Twoim urządzeniu wystąpił problem wewnętrzny. Może być ono niestabilne, dopóki nie przywrócisz danych fabrycznych."</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index a219276..173be30 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1948,6 +1948,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> a <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> a <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Qualquer agenda"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> está silenciando alguns sons"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Há um problema interno com seu dispositivo. Ele pode ficar instável até que você faça a redefinição para configuração original."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index a898121..605e94e 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1948,6 +1948,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Qualquer calendário"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> está a desativar alguns sons."</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Existe um problema interno no seu dispositivo e pode ficar instável até efetuar uma reposição de dados de fábrica."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index a219276..173be30 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1948,6 +1948,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> a <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> a <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Qualquer agenda"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> está silenciando alguns sons"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Há um problema interno com seu dispositivo. Ele pode ficar instável até que você faça a redefinição para configuração original."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 8b7a296..b709475 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1948,6 +1948,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Orice calendar"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> dezactivează anumite sunete"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"A apărut o problemă internă pe dispozitiv, iar acesta poate fi instabil până la revenirea la setările din fabrică."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 386830e..b3f75ca 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1949,6 +1949,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Любой календарь"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> приглушает некоторые звуки."</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Произошла внутренняя ошибка, и устройство может работать нестабильно, пока вы не выполните сброс настроек."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index e969a8e..2dee88c 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="END">%2$s</xliff:g> සිට <xliff:g id="START">%1$s</xliff:g> දක්වා"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"ඕනෑම දින දර්ශනයක්"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> සමහර ශබ්ද නිහඬ කරමින්"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"ඔබේ උපාංගය සමගින් ගැටලුවක් ඇති අතර, ඔබේ කර්මාන්තශාලා දත්ත යළි සකසන තෙක් එය අස්ථායි විය හැකිය."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index d211d8c..177a55b 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1949,6 +1949,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Ľubovoľný kalendár"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> vypína niektoré zvuky"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Vo vašom zariadení došlo k internému problému. Môže byť nestabilné, kým neobnovíte jeho výrobné nastavenia."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index ca85434..28ca698 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1949,6 +1949,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> do <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Kateri koli koledar"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> izklaplja nekatere zvoke"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Vaša naprava ima notranjo napako in bo morda nestabilna, dokler je ne ponastavite na tovarniške nastavitve."</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 45cf31a..7b4bc79 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Çdo kalendar"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> po çaktivizon disa tinguj"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Ka një problem të brendshëm me pajisjen tënde. Ajo mund të jetë e paqëndrueshme derisa të rivendosësh të dhënat në gjendje fabrike."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 5a3bae0..fe499c7 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1948,6 +1948,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Било који календар"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> искључује неке звуке"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Дошло је до интерног проблема у вези са уређајем и можда ће бити нестабилан док не обавите ресетовање на фабричка подешавања."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index fde9023..e037046 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> till <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Alla kalendrar"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> stänger av vissa ljud"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Ett internt problem har uppstått i enheten, och det kan hända att problemet kvarstår tills du återställer standardinställningarna."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 2a62c87..dde0637 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> hadi <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Kalenda yoyote"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> inazima baadhi ya sauti"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Kuna hitilafu ya ndani ya kifaa chako, na huenda kisiwe thabiti mpaka urejeshe mipangilio ya kiwandani."</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 6ff96c0..42cf38b 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> முதல் <xliff:g id="END">%2$s</xliff:g> வரை"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"ஏதேனும் கேலெண்டர்"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> சில ஒலிகளை முடக்குகிறது"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"சாதனத்தில் அகச் சிக்கல் இருக்கிறது, அதனை ஆரம்பநிலைக்கு மீட்டமைக்கும் வரை நிலையற்று இயங்கலாம்."</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 68fce1f..c867d55 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> నుండి <xliff:g id="END">%2$s</xliff:g> వరకు"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"ఏదైనా క్యాలెండర్"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> కొన్ని ధ్వనులను మ్యూట్ చేస్తోంది"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"మీ పరికరంతో అంతర్గత సమస్య ఏర్పడింది మరియు మీరు ఫ్యాక్టరీ డేటా రీసెట్ చేసే వరకు అస్థిరంగా ఉంటుంది."</string>
@@ -2442,7 +2444,7 @@
     <string name="satellite_sos_not_in_allowed_region_notification_title" msgid="3164093193467075926">"ఎమర్జెన్సీ శాటిలైట్ సహాయం అందుబాటులో లేదు"</string>
     <string name="satellite_sos_not_in_allowed_region_notification_summary" msgid="7686947667515679672">"ఈ దేశంలో లేదా ప్రాంతంలో ఎమర్జెన్సీ శాటిలైట్ సహాయం అందుబాటులో లేదు"</string>
     <string name="satellite_sos_unsupported_default_sms_app_notification_title" msgid="292528603128702080">"ఎమర్జెన్సీ శాటిలైట్ సహాయం సెటప్ చేయలేదు"</string>
-    <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"శాటిలైట్ ద్వారా మెసేజ్ చేయడానికి, Google Messagesను మీ ఆటోమేటిక్ సెట్టింగ్ మెసేజింగ్ యాప్‌గా సెట్ చేయండి"</string>
+    <string name="satellite_sos_unsupported_default_sms_app_notification_summary" msgid="3165168393504548437">"శాటిలైట్ ద్వారా మెసేజ్ చేయడానికి, Google Messagesను మీ ఆటోమేటిక్ మెసేజింగ్ యాప్‌గా సెట్ చేయండి"</string>
     <string name="satellite_sos_location_disabled_notification_title" msgid="5427987916850950591">"ఎమర్జెన్సీ శాటిలైట్ సహాయం అందుబాటులో లేదు"</string>
     <string name="satellite_sos_location_disabled_notification_summary" msgid="1544937460641058567">"ఈ దేశంలో లేదా ప్రాంతంలో ఎమర్జెన్సీ శాటిలైట్ సహాయం అందుబాటులో ఉందో లేదో చెక్ చేయడానికి, లొకేషన్ సెట్టింగ్‌లను ఆన్ చేయండి"</string>
     <string name="satellite_messaging_available_notification_title" msgid="3366657987618784706">"శాటిలైట్ మెసేజింగ్ అందుబాటులో ఉంది"</string>
@@ -2454,7 +2456,7 @@
     <string name="satellite_messaging_not_in_allowed_region_notification_title" msgid="2035303593479031655">"శాటిలైట్ మెసేజింగ్ అందుబాటులో లేదు"</string>
     <string name="satellite_messaging_not_in_allowed_region_notification_summary" msgid="5270294879531815854">"ఈ దేశంలో లేదా ప్రాంతంలో శాటిలైట్ మెసేజింగ్ అందుబాటులో లేదు"</string>
     <string name="satellite_messaging_unsupported_default_sms_app_notification_title" msgid="1004808759472360189">"శాటిలైట్ మెసేజింగ్‌ను సెటప్ చేయలేదు"</string>
-    <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"శాటిలైట్ ద్వారా మెసేజ్ చేయడానికి, Google Messagesను మీ ఆటోమేటిక్ సెట్టింగ్ మెసేజింగ్ యాప్‌గా సెట్ చేయండి"</string>
+    <string name="satellite_messaging_unsupported_default_sms_app_notification_summary" msgid="17084124893763593">"శాటిలైట్ ద్వారా మెసేజ్ చేయడానికి, Google Messagesను మీ ఆటోమేటిక్ మెసేజింగ్ యాప్‌గా సెట్ చేయండి"</string>
     <string name="satellite_messaging_location_disabled_notification_title" msgid="7270641894250928494">"శాటిలైట్ మెసేజింగ్ అందుబాటులో లేదు"</string>
     <string name="satellite_messaging_location_disabled_notification_summary" msgid="1450824950686221810">"ఈ దేశంలో లేదా ప్రాంతంలో శాటిలైట్ మెసేజింగ్ అందుబాటులో ఉందో లేదో చెక్ చేయడానికి, లొకేషన్ సెట్టింగ్‌లను ఆన్ చేయండి"</string>
     <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"వేలిముద్ర అన్‌లాక్‌ను మళ్లీ సెటప్ చేయండి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 178a76d..7af9fb9c 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g>ถึง<xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"ปฏิทินทั้งหมด"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> กำลังปิดเสียงบางรายการ"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"อุปกรณ์ของคุณเกิดปัญหาภายในเครื่อง อุปกรณ์อาจทำงานไม่เสถียรจนกว่าคุณจะรีเซ็ตข้อมูลเป็นค่าเริ่มต้น"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 8e3c5e7..5de981c 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>, <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> patungong <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Anumang kalendaryo"</string>
     <string name="muted_by" msgid="91464083490094950">"Minu-mute ng <xliff:g id="THIRD_PARTY">%1$s</xliff:g> ang ilang tunog"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"May internal na problema sa iyong device, at maaaring hindi ito maging stable hanggang sa i-reset mo ang factory data."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 98b1dd3..28eb1253 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>-<xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g>-<xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Tüm takvimler"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> bazı sesleri kapatıyor"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Cihazınızla ilgili dahili bir sorun oluştu ve fabrika verilerine sıfırlama işlemi gerçekleştirilene kadar kararsız çalışabilir."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index d5e6bd8..ae2cab5 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1949,6 +1949,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"З усіх календарів"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> вимикає деякі звуки"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Через внутрішню помилку ваш пристрій може працювати нестабільно. Відновіть заводські налаштування."</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index b26b1c1..6a96bc2 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">"، "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> تا <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"کوئی بھی کیلنڈر"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> کچھ آوازوں کو خاموش کر رہا ہے"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"آپ کے آلہ میں ایک داخلی مسئلہ ہے اور جب تک آپ فیکٹری ڈیٹا کو دوبارہ ترتیب نہیں دے دیتے ہیں، ہوسکتا ہے کہ یہ غیر مستحکم رہے۔"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 97e0448..42b236a 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Har qanday taqvim"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ayrim tovushlarni ovozsiz qilgan"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Qurilmangiz bilan bog‘liq ichki muammo mavjud. U zavod sozlamalari tiklanmaguncha barqaror ishlamasligi mumkin."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 1ebff32..ae39763 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> đến <xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Bất kỳ lịch nào"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> đang tắt một số âm thanh"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Đã xảy ra sự cố nội bộ với thiết bị của bạn và thiết bị có thể sẽ không ổn định cho tới khi bạn thiết lập lại dữ liệu ban đầu."</string>
diff --git a/core/res/res/values-watch-v36/config.xml b/core/res/res/values-watch-v36/config.xml
index 1143ae3..679dc70 100644
--- a/core/res/res/values-watch-v36/config.xml
+++ b/core/res/res/values-watch-v36/config.xml
@@ -16,5 +16,5 @@
 
 <resources>
     <dimen name="config_wearMaterial3_buttonCornerRadius">26dp</dimen>
-    <dimen name="config_bottomDialogCornerRadius">18dp</dimen>
+    <dimen name="config_wearMaterial3_bottomDialogCornerRadius">18dp</dimen>
 </resources>
diff --git a/core/res/res/values-watch-v36/dimens_material.xml b/core/res/res/values-watch-v36/dimens_material.xml
index ffa3b9c..7232786 100644
--- a/core/res/res/values-watch-v36/dimens_material.xml
+++ b/core/res/res/values-watch-v36/dimens_material.xml
@@ -31,4 +31,9 @@
     <!-- Opacity factor for disabled material3 widget -->
     <dimen name="disabled_alpha_device_default">0.12</dimen>
     <dimen name="primary_content_alpha_device_default">0.38</dimen>
+
+    <!--  values for material3 progress bar(progress indicator)  -->
+    <item name="progressbar_inner_radius_ratio" format="float" type="dimen">2.12</item>
+    <dimen name="progressbar_thickness">8dp</dimen>
+    <dimen name="progressbar_elevation">0.1dp</dimen>
 </resources>
diff --git a/core/res/res/values-watch-v36/styles_material.xml b/core/res/res/values-watch-v36/styles_material.xml
index 00f3f09..20f4095 100644
--- a/core/res/res/values-watch-v36/styles_material.xml
+++ b/core/res/res/values-watch-v36/styles_material.xml
@@ -57,7 +57,7 @@
     </style>
 
     <!--  AlertDialog Styles  -->
-    <style name="Widget.DeviceDefault.Button.ButtonBar.AlertDialog" parent="Widget.DeviceDefault.Button">
+    <style name="Widget.DeviceDefault.Button.ButtonBar.AlertDialog.WearMaterial3" parent="Widget.DeviceDefault.Button">
         <item name="android:textSize">0sp</item>
         <item name="android:gravity">center</item>
         <item name="android:paddingStart">0dp</item>
@@ -65,18 +65,27 @@
         <item name="android:drawablePadding">0dp</item>
     </style>
 
-    <style name="Widget.DeviceDefault.Button.ButtonBar.AlertDialog.Confirm" parent="Widget.DeviceDefault.Button.ButtonBar.AlertDialog">
+    <style name="Widget.DeviceDefault.Button.ButtonBar.AlertDialog.WearMaterial3.Confirm">
         <!-- Use a ImageView as background -->
         <item name="background">@android:color/transparent</item>
         <item name="minWidth">@dimen/dialog_btn_confirm_width</item>
         <item name="minHeight">@dimen/dialog_btn_confirm_height</item>
     </style>
 
-    <style name="Widget.DeviceDefault.Button.ButtonBar.AlertDialog.Negative" parent="Widget.DeviceDefault.Button.ButtonBar.AlertDialog">
+    <style name="Widget.DeviceDefault.Button.ButtonBar.AlertDialog.WearMaterial3.Negative">
         <item name="background">@drawable/dialog_alert_button_negative</item>
         <item name="minWidth">@dimen/dialog_btn_negative_width</item>
         <item name="minHeight">@dimen/dialog_btn_negative_height</item>
         <item name="maxWidth">@dimen/dialog_btn_negative_width</item>
         <item name="maxHeight">@dimen/dialog_btn_negative_height</item>
     </style>
+
+    <!-- Wear Material3 Progress Bar style: progressed ring.-->
+    <style name="Widget.DeviceDefault.ProgressBar.WearMaterial3">
+        <item name="indeterminateOnly">false</item>
+        <item name="progressDrawable">@drawable/progress_ring_wear_material3</item>
+        <item name="minHeight">@dimen/progress_bar_height</item>
+        <item name="maxHeight">@dimen/progress_bar_height</item>
+        <item name="mirrorForRtl">true</item>
+    </style>
 </resources>
\ No newline at end of file
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 64c2f70..fbab421 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">"、 "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g>到<xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"所有日历"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>正在将某些音效设为静音"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"您的设备内部出现了问题。如果不将设备恢复出厂设置,设备运行可能会不稳定。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 53c5d15..43da71e 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">"、 "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g>至<xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"任何日曆"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>正將某些音效設為靜音"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"你裝置的系統發生問題,回復原廠設定後即可解決該問題。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index cbd6bd2..628fda7 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">"、 "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g>到<xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"任何日曆"</string>
     <string name="muted_by" msgid="91464083490094950">"「<xliff:g id="THIRD_PARTY">%1$s</xliff:g>」正在關閉部分音效"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"你的裝置發生內部問題,必須將裝置恢復原廠設定才能解除不穩定狀態。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index f498fe2..878275a8 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1947,6 +1947,8 @@
     <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string>
     <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>, <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"U-<xliff:g id="START">%1$s</xliff:g> ukuya ku-<xliff:g id="END">%2$s</xliff:g>"</string>
+    <!-- no translation found for zen_mode_trigger_summary_combined (6492381546327807669) -->
+    <skip />
     <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Noma iyiphi ikhalenda"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ithulisa eminye imisindo"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Kukhona inkinga yangaphakathi ngedivayisi yakho, futhi ingase ibe engazinzile kuze kube yilapho usetha kabusha yonke idatha."</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index f6590b1..8c46ccc 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4808,6 +4808,12 @@
         <!-- Whether the device should default to observe mode when this service is
              default or in the foreground. -->
         <attr name="shouldDefaultToObserveMode" format="boolean"/>
+        <!-- Whether this service should share the same AID routing priority as the role
+             owner. This package and the role owner must have the same signature, and the
+             role owner must opt into this behavior by using the property named by
+             {@link android.nfc.cardemulation.CardEmulation.PROPERTY_ALLOW_SHARED_ROLE_PRIORITY }
+             in the <code>&lt;application&rt;</code> tag. -->
+        <attr name="shareRolePriority" format="boolean"/>
     </declare-styleable>
 
     <!-- Use <code>offhost-apdu-service</code> as the root tag of the XML resource that
@@ -4835,6 +4841,7 @@
         <!-- Whether the device should default to observe mode when this service is
              default or in the foreground. -->
         <attr name="shouldDefaultToObserveMode"/>
+        <attr name="shareRolePriority"/>
     </declare-styleable>
 
     <!-- Specify one or more <code>aid-group</code> elements inside a
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 7ef5394..08cb4de 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1867,8 +1867,12 @@
          16 KB device. 4 KB natives libs will be loaded app-compat mode if they are eligible.
          @FlaggedApi(android.content.pm.Flags.FLAG_APP_COMPAT_OPTION_16KB) -->
     <attr name="pageSizeCompat">
-        <enum name="enabled" value="5" />
-        <enum name="disabled" value="6" />
+        <!-- value for enabled must match with
+        ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_ENABLED -->
+        <enum name="enabled" value="32" />
+        <!-- value for disabled must match with
+        ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_DISABLED -->
+        <enum name="disabled" value="64" />
     </attr>
 
 
@@ -2568,6 +2572,8 @@
              against a development branch, in which case it will only work against
              the development builds. -->
         <attr name="minSdkVersion" format="integer|string" />
+        <!-- @FlaggedApi(android.content.pm.Flags.FLAG_SUPPORT_MINOR_VERSIONS_IN_MINSDKVERSION) -->
+        <attr name="minSdkVersionFull" format="string" />
         <!-- This is the SDK version number that the application is targeting.
              It is able to run on older versions (down to minSdkVersion), but
              was explicitly tested to work with the version specified here.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7f2c816..0d13ca8 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2731,6 +2731,8 @@
     </string-array>
     <!-- The list of supported dream complications -->
     <integer-array name="config_supportedDreamComplications">
+        <!-- COMPLICATION_TYPE_TIME -->
+        <item>1</item>
     </integer-array>
 
     <!-- Are we allowed to dream while not plugged in? -->
@@ -2777,6 +2779,9 @@
          If empty, logs "other" for all. -->
     <string-array name="config_loggable_dream_prefixes"></string-array>
 
+    <!-- Whether to enable glanceable hub features on this device. -->
+    <bool name="config_glanceableHubEnabled">false</bool>
+
     <!-- ComponentName of a dream to show whenever the system would otherwise have
          gone to sleep.  When the PowerManager is asked to go to sleep, it will instead
          try to start this dream if possible.  The dream should typically call startDozing()
@@ -6001,6 +6006,12 @@
     <!-- If true, show multiuser switcher by default unless the user specifically disables it. -->
     <bool name="config_showUserSwitcherByDefault">false</bool>
 
+    <!-- If true, user can change state of multiuser switcher. -->
+    <bool name="config_allowChangeUserSwitcherEnabled">true</bool>
+
+    <!-- If true, multiuser switcher would be automatically enabled when second user is created on the device. -->
+    <bool name="config_enableUserSwitcherUponUserCreation">true</bool>
+
     <!-- Set to true to make assistant show in front of the dream/screensaver. -->
     <bool name="config_assistantOnTopOfDream">false</bool>
 
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index c8df662..f53acbf 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -255,6 +255,19 @@
      This represents 16dp for the left margin + 40dp for the icon + 16dp for the right margin -->
     <dimen name="notification_2025_content_margin_start">72dp</dimen>
 
+    <!-- The margin on the start of the media actions, selected to ensure that action icons which
+     are visually 12x12 in a 24x24 drawable will align correctly with the text.  This means that
+     stock media action icons will align, but icons may be visually up to 20x20 and remain in-spec,
+     in which case they will protrude into the start column slightly.
+     72dp (content margin) - 8dp (media action padding) - 6dp (visual padding within drawable) -->
+    <dimen name="notification_2025_media_actions_margin_start">58dp</dimen>
+
+    <!-- The margin on the start of notification actions (2025 redesign version), to align them to
+     the rest of the notification content. Note that this can be set to 0 if the actions would not
+     fit with it included.
+     72dp (content margin) - 12dp (action padding) - 4dp (button inset) -->
+    <dimen name="notification_2025_actions_margin_start">56dp</dimen>
+
     <!-- The margin on the end of most content views (ignores the expander) -->
     <dimen name="notification_content_margin_end">16dp</dimen>
 
@@ -377,6 +390,9 @@
     <!-- the size of the notification close button -->
     <dimen name="notification_close_button_size">16dp</dimen>
 
+    <!-- Margin for all notification content -->
+    <dimen name="notification_2025_margin">16dp</dimen>
+
     <!-- Vertical margin for the headerless notification content, when content has 1 line -->
     <!-- 16 * 2 (margins) + 24 (1 line) = 56 (notification) -->
     <dimen name="notification_headerless_margin_oneline">16dp</dimen>
@@ -388,10 +404,19 @@
     <!-- The height of each of the 1 or 2 lines in the headerless notification template -->
     <dimen name="notification_headerless_line_height">24dp</dimen>
 
-    <!-- vertical margin for the headerless notification content -->
+    <!-- The minimum height of the notification content (even when there's only one line of text) -->
+    <dimen name="notification_2025_content_min_height">40dp</dimen>
+
+    <!-- Height of a headerless notification with one or two lines -->
+    <!-- 16 * 2 (margins) + 40 (min content height) = 72 (notification) -->
+    <dimen name="notification_2025_min_height">72dp</dimen>
+
+    <!-- Height of a headerless notification with one line -->
+    <!-- 16 * 2 (margins) + 24 (1 line) = 56 (notification) -->
     <dimen name="notification_headerless_min_height">56dp</dimen>
 
-    <!-- Height of a small notification in the status bar -->
+    <!-- Height of a small two-line notification -->
+    <!-- 20 * 2 (margins) + 24 * 2 (2 lines) = 88 (notification) -->
     <dimen name="notification_min_height">88dp</dimen>
 
     <!-- The width of the big icons in notifications. -->
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index e71277d..3b39a65 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -290,4 +290,7 @@
 
   <!-- View tag associating a view with its overridden id, to ensure valid recycling only. -->
   <item type="id" name="remote_views_override_id" />
+
+  <!-- View tag associating a view with its id for widget metrics. -->
+  <item type="id" name="remoteViewsMetricsId" />
 </resources>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index b0b87d1d..76ff565 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -133,9 +133,15 @@
     <public name="alternateLauncherLabels"/>
     <!-- @FlaggedApi(android.content.pm.Flags.FLAG_APP_COMPAT_OPTION_16KB) -->
     <public name="pageSizeCompat" />
+    <!-- @FlaggedApi(android.nfc.Flags.FLAG_NFC_ASSOCIATED_ROLE_SERVICES) -->
+    <public name="shareRolePriority"/>
+    <!-- @FlaggedApi(android.content.pm.Flags.FLAG_SUPPORT_MINOR_VERSIONS_IN_MINSDKVERSION) -->
+    <public name="minSdkVersionFull"/>
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01b60000">
+    <!-- @FlaggedApi(android.appwidget.flags.Flags.FLAG_ENGAGEMENT_METRICS) -->
+    <public name="remoteViewsMetricsId"/>
   </staging-public-group>
 
   <staging-public-group type="style" first-id="0x01b50000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index c13fdb1..d498b91 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -199,6 +199,21 @@
     <!-- Displayed to confirm to the user that caller ID will not be restricted on the next call or in general. -->
     <string name="CLIRDefaultOffNextCallOff">Caller ID defaults to not restricted. Next call: Not restricted</string>
 
+    <!-- Message displayed in dialog when APK is not 16 KB aligned. [CHAR LIMIT=NONE] -->
+    <string name="page_size_compat_apk_warning">This app isn’t 16 KB compatible. APK alignment check failed.
+        This app will be run using page size compatible mode. For best compatibility, please recompile the application with 16 KB support.
+        For more information, see &lt;a href=\"https://developer.android.com/16kb-page-size\"&gt;https://developer.android.com/16kb-page-size&lt;/a&gt; </string>
+
+    <!-- Message displayed in dialog when ELF is not 16 KB aligned. [CHAR LIMIT=NONE] -->
+    <string name="page_size_compat_elf_warning">This app isn’t 16 KB compatible. ELF alignment check failed.
+        This app will be run using page size compatible mode. For best compatibility, please recompile the application with 16 KB support.
+        For more information, see &lt;a href=\"https://developer.android.com/16kb-page-size\"&gt;https://developer.android.com/16kb-page-size&lt;/a&gt;</string>
+
+    <!-- Message displayed in dialog when APK and ELF are not 16 KB aligned. [CHAR LIMIT=NONE] -->
+    <string name="page_size_compat_apk_and_elf_warning">This app isn’t 16 KB compatible. APK and ELF alignment checks failed.
+        This app will be run using page size compatible mode. For best compatibility, please recompile the application with 16 KB support.
+        For more information, see &lt;a href=\"https://developer.android.com/16kb-page-size\"&gt;https://developer.android.com/16kb-page-size&lt;/a&gt;</string>
+
 
     <!-- Displayed to tell the user that caller ID is not provisioned for their SIM. -->
     <string name="serviceNotProvisioned">Service not provisioned.</string>
@@ -5357,6 +5372,8 @@
     <string name="zen_mode_trigger_summary_range_symbol_combination"><xliff:g id="start" example="Sun">%1$s</xliff:g> - <xliff:g id="end" example="Thu">%2$s</xliff:g></string>
     <!-- [CHAR LIMIT=40] General template for a start - end range in a text summary, used for the trigger description of a Zen mode -->
     <string name="zen_mode_trigger_summary_range_words"><xliff:g id="start" example="Sunday">%1$s</xliff:g> to <xliff:g id="end" example="Thursday">%2$s</xliff:g></string>
+    <!-- [CHAR LIMIT=NONE] General template for combining a days of week start-end range with a time-based start-end range, for example: "Sun-Thurs, 10:00 PM - 7:00 AM" -->
+    <string name="zen_mode_trigger_summary_combined"><xliff:g id="days" example="Sat-Thurs">%1$s</xliff:g>,\u0020<xliff:g id="times" example="10:00 PM - 7:00 AM">%2$s</xliff:g></string>
     <!-- [CHAR LIMIT=40] Event-based rule calendar option value for any calendar, used for the trigger description of a Zen mode -->
     <string name="zen_mode_trigger_event_calendar_any">Any calendar</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b49e142..748f4b3 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2054,6 +2054,7 @@
   <java-symbol type="bool" name="config_allowTheaterModeWakeFromDock" />
   <java-symbol type="bool" name="config_allowTheaterModeWakeFromWindowLayout" />
   <java-symbol type="bool" name="config_keepDreamingWhenUnplugging" />
+  <java-symbol type="bool" name="config_glanceableHubEnabled" />
   <java-symbol type="integer" name="config_keyguardDrawnTimeout" />
   <java-symbol type="bool" name="config_goToSleepOnButtonPressTheaterMode" />
   <java-symbol type="bool" name="config_supportLongPressPowerWhenNonInteractive" />
@@ -2390,8 +2391,17 @@
   <java-symbol type="layout" name="notification_material_action_list" />
   <java-symbol type="layout" name="notification_material_action_tombstone" />
   <java-symbol type="layout" name="notification_2025_template_collapsed_base" />
+  <java-symbol type="layout" name="notification_2025_template_expanded_base" />
   <java-symbol type="layout" name="notification_2025_template_heads_up_base" />
   <java-symbol type="layout" name="notification_2025_template_header" />
+  <java-symbol type="layout" name="notification_2025_template_collapsed_messaging" />
+  <java-symbol type="layout" name="notification_2025_template_collapsed_media" />
+  <java-symbol type="layout" name="notification_2025_template_expanded_big_picture" />
+  <java-symbol type="layout" name="notification_2025_template_expanded_inbox" />
+  <java-symbol type="layout" name="notification_2025_template_expanded_media" />
+  <java-symbol type="layout" name="notification_2025_template_expanded_big_text" />
+  <java-symbol type="layout" name="notification_2025_template_expanded_messaging" />
+  <java-symbol type="layout" name="notification_2025_template_expanded_progress" />
   <java-symbol type="layout" name="notification_template_material_base" />
   <java-symbol type="layout" name="notification_template_material_heads_up_base" />
   <java-symbol type="layout" name="notification_template_material_compact_heads_up_base" />
@@ -2403,6 +2413,8 @@
   <java-symbol type="layout" name="notification_template_material_big_media" />
   <java-symbol type="layout" name="notification_template_material_big_text" />
   <java-symbol type="layout" name="notification_template_material_progress" />
+  <java-symbol type="layout" name="notification_template_material_messaging" />
+  <java-symbol type="layout" name="notification_template_material_big_messaging" />
   <java-symbol type="layout" name="notification_template_header" />
   <java-symbol type="layout" name="notification_material_media_action" />
   <java-symbol type="color" name="notification_progress_background_color" />
@@ -2666,6 +2678,7 @@
   <java-symbol type="string" name="zen_mode_trigger_summary_divider_text" />
   <java-symbol type="string" name="zen_mode_trigger_summary_range_symbol_combination" />
   <java-symbol type="string" name="zen_mode_trigger_summary_range_words" />
+  <java-symbol type="string" name="zen_mode_trigger_summary_combined" />
   <java-symbol type="string" name="zen_mode_trigger_event_calendar_any" />
 
   <java-symbol type="string" name="display_rotation_camera_compat_toast_after_rotation" />
@@ -3308,6 +3321,11 @@
   <java-symbol type="string" name="language_selection_title" />
   <java-symbol type="string" name="search_language_hint" />
 
+  <!-- Strings for page size app compat dialog -->
+  <java-symbol type="string" name="page_size_compat_apk_warning" />
+  <java-symbol type="string" name="page_size_compat_elf_warning" />
+  <java-symbol type="string" name="page_size_compat_apk_and_elf_warning" />
+
   <!--  Work profile unlaunchable app alert dialog-->
   <java-symbol type="style" name="AlertDialogWithEmergencyButton"/>
   <java-symbol type="string" name="work_mode_emergency_call_button" />
@@ -3336,8 +3354,6 @@
   <java-symbol type="bool" name="config_strongAuthRequiredOnBoot" />
 
   <java-symbol type="layout" name="app_anr_dialog" />
-  <java-symbol type="layout" name="notification_template_material_messaging" />
-  <java-symbol type="layout" name="notification_template_material_big_messaging" />
 
   <java-symbol type="id" name="aerr_wait" />
 
@@ -3439,6 +3455,8 @@
   <!-- Notifications: CallStyle -->
   <java-symbol type="layout" name="notification_template_material_call" />
   <java-symbol type="layout" name="notification_template_material_big_call" />
+  <java-symbol type="layout" name="notification_2025_template_collapsed_call" />
+  <java-symbol type="layout" name="notification_2025_template_expanded_call" />
   <java-symbol type="string" name="call_notification_answer_action" />
   <java-symbol type="string" name="call_notification_answer_video_action" />
   <java-symbol type="string" name="call_notification_decline_action" />
@@ -3463,6 +3481,7 @@
 
   <java-symbol type="bool" name="config_supportPreRebootSecurityLogs" />
 
+  <java-symbol type="dimen" name="notification_2025_actions_margin_start"/>
   <java-symbol type="id" name="notification_action_list_margin_target" />
   <java-symbol type="dimen" name="notification_actions_padding_start"/>
   <java-symbol type="dimen" name="notification_actions_collapsed_priority_width"/>
@@ -4090,6 +4109,7 @@
   <java-symbol type="layout" name="notification_template_messaging_text_message" />
   <java-symbol type="layout" name="notification_template_messaging_image_message" />
   <java-symbol type="layout" name="notification_template_messaging_group" />
+  <java-symbol type="layout" name="notification_2025_messaging_group" />
   <java-symbol type="id" name="message_text" />
   <java-symbol type="id" name="message_name" />
   <java-symbol type="id" name="message_icon" />
@@ -4620,9 +4640,11 @@
   <java-symbol type="dimen" name="conversation_icon_container_top_padding" />
   <java-symbol type="dimen" name="conversation_icon_container_top_padding_small_avatar" />
   <java-symbol type="layout" name="notification_template_material_conversation" />
+  <java-symbol type="layout" name="notification_2025_template_conversation" />
   <java-symbol type="dimen" name="button_padding_horizontal_material" />
   <java-symbol type="dimen" name="button_inset_horizontal_material" />
   <java-symbol type="layout" name="conversation_face_pile_layout" />
+  <java-symbol type="layout" name="notification_2025_conversation_face_pile_layout" />
   <java-symbol type="string" name="unread_convo_overflow" />
   <java-symbol type="drawable" name="conversation_badge_background" />
   <java-symbol type="drawable" name="conversation_badge_ring" />
@@ -4693,6 +4715,8 @@
 
   <!-- If true, show multiuser switcher by default unless the user specifically disables it. -->
   <java-symbol type="bool" name="config_showUserSwitcherByDefault" />
+  <java-symbol type="bool" name="config_allowChangeUserSwitcherEnabled" />
+  <java-symbol type="bool" name="config_enableUserSwitcherUponUserCreation" />
 
   <!-- Set to true to make assistant show in front of the dream/screensaver. -->
   <java-symbol type="bool" name="config_assistantOnTopOfDream"/>
@@ -5109,7 +5133,6 @@
   <java-symbol type="layout" name="notification_expand_button"/>
   <java-symbol type="id" name="close_button" />
   <java-symbol type="layout" name="notification_close_button"/>
-  <java-symbol type="id" name="notification_buttons_column" />
 
   <java-symbol type="bool" name="config_supportsMicToggle" />
   <java-symbol type="bool" name="config_supportsCamToggle" />
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/drawable-mdpi/border_ltr.9.png b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable-mdpi/border_ltr.9.png
new file mode 100644
index 0000000..c7e937c
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable-mdpi/border_ltr.9.png
Binary files differ
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/drawable-mdpi/border_tr.9.png b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable-mdpi/border_tr.9.png
new file mode 100644
index 0000000..a3cff98
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable-mdpi/border_tr.9.png
Binary files differ
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/power_other_24.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/power_other_24.xml
new file mode 100644
index 0000000..c9fb53e
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/power_other_24.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:tint="?attr/colorControlNormal"
+    android:viewportHeight="960"
+    android:viewportWidth="960">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M720,600L720,520L800,520Q817,520 828.5,531.5Q840,543 840,560Q840,577 828.5,588.5Q817,600 800,600L720,600ZM720,760L720,680L800,680Q817,680 828.5,691.5Q840,703 840,720Q840,737 828.5,748.5Q817,760 800,760L720,760ZM560,800Q527,800 503.5,776.5Q480,753 480,720L400,720L400,560L480,560Q480,527 503.5,503.5Q527,480 560,480L680,480L680,800L560,800ZM280,680Q214,680 167,633Q120,586 120,520Q120,454 167,407Q214,360 280,360L340,360Q365,360 382.5,342.5Q400,325 400,300Q400,275 382.5,257.5Q365,240 340,240L200,240Q183,240 171.5,228.5Q160,217 160,200Q160,183 171.5,171.5Q183,160 200,160L340,160Q398,160 439,201Q480,242 480,300Q480,358 439,399Q398,440 340,440L280,440Q247,440 223.5,463.5Q200,487 200,520Q200,553 223.5,576.5Q247,600 280,600L360,600L360,680L280,680Z" />
+</vector>
\ No newline at end of file
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/screen_off_24.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/screen_off_24.xml
new file mode 100644
index 0000000..ca94825
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/screen_off_24.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:tint="?attr/colorControlNormal"
+    android:viewportHeight="960"
+    android:viewportWidth="960">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M280,920Q247,920 223.5,896.5Q200,873 200,840L200,120Q200,87 223.5,63.5Q247,40 280,40L680,40Q713,40 736.5,63.5Q760,87 760,120L760,840Q760,873 736.5,896.5Q713,920 680,920L280,920ZM280,800L280,840Q280,840 280,840Q280,840 280,840L680,840Q680,840 680,840Q680,840 680,840L680,800L280,800ZM280,720L680,240L280,720ZM280,160L680,160L680,120Q680,120 680,120Q680,120 680,120L280,120Q280,120 280,120Q280,120 280,120L280,160ZM280,160L280,120Q280,120 280,120Q280,120 280,120L280,120Q280,120 280,120Q280,120 280,120L280,160ZM280,800L280,800L280,840Q280,840 280,840Q280,840 280,840L280,840Q280,840 280,840Q280,840 280,840L280,800Z" />
+</vector>
\ No newline at end of file
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/screen_on_24.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/screen_on_24.xml
new file mode 100644
index 0000000..48f990c
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/screen_on_24.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:tint="?attr/colorControlNormal"
+    android:viewportHeight="960"
+    android:viewportWidth="960">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M280,920Q247,920 223.5,896.5Q200,873 200,840L200,120Q200,87 223.5,63.5Q247,40 280,40L680,40Q713,40 736.5,63.5Q760,87 760,120L760,840Q760,873 736.5,896.5Q713,920 680,920L280,920ZM280,800L280,840Q280,840 280,840Q280,840 280,840L680,840Q680,840 680,840Q680,840 680,840L680,800L280,800ZM280,720L680,720L680,240L280,240L280,720ZM280,160L680,160L680,120Q680,120 680,120Q680,120 680,120L280,120Q280,120 280,120Q280,120 280,120L280,160ZM280,160L280,120Q280,120 280,120Q280,120 280,120L280,120Q280,120 280,120Q280,120 280,120L280,160ZM280,800L280,800L280,840Q280,840 280,840Q280,840 280,840L280,840Q280,840 280,840Q280,840 280,840L280,800Z" />
+</vector>
\ No newline at end of file
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml
index be0e135..e1f4623 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
   ~ Copyright (C) 2020 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,46 +13,127 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:orientation="horizontal"
-    android:minHeight="?android:attr/listPreferredItemHeightSmall"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:paddingTop="8dp"
-    android:paddingBottom="8dp">
+    android:orientation="vertical">
 
-    <ImageView
-        android:id="@+id/icon"
-        android:layout_width="wrap_content"
+    <LinearLayout
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
-        android:layout_marginEnd="8dp"
-        android:paddingBottom="8dp"/>
+        android:minHeight="?android:attr/listPreferredItemHeightSmall"
+        android:orientation="horizontal"
+        android:paddingBottom="8dp"
+        android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+        android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+        android:paddingTop="8dp">
 
-    <TextView
-        android:id="@+id/title"
-        android:layout_width="0dp"
-        android:layout_weight="1"
-        android:layout_height="wrap_content"
-        android:textAppearance="@style/TextAppearanceBody"/>
+        <ImageView
+            android:id="@+id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_marginEnd="8dp"
+            android:paddingBottom="8dp" />
 
-    <TextView
-        android:id="@+id/value1"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="8dp"
-        android:gravity="right"
-        android:maxLines="1"
-        android:textAppearance="@style/TextAppearanceBody"/>
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:textAppearance="@style/TextAppearanceBody" />
 
-    <TextView
-        android:id="@+id/value2"
-        android:layout_width="76dp"
+        <TextView
+            android:id="@+id/value1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="8dp"
+            android:gravity="right"
+            android:maxLines="1"
+            android:textAppearance="@style/TextAppearanceBody" />
+
+        <TextView
+            android:id="@+id/value2"
+            android:layout_width="76dp"
+            android:layout_height="wrap_content"
+            android:gravity="right"
+            android:maxLines="1"
+            android:textAppearance="@style/TextAppearanceBody" />
+    </LinearLayout>
+
+    <TableLayout
+        android:id="@+id/table"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:gravity="right"
-        android:maxLines="1"
-        android:textAppearance="@style/TextAppearanceBody"/>
+        android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd"
+        android:layout_marginStart="50dp"
+        android:stretchColumns="1,2,3,4">
+
+        <TableRow android:background="#EEFFEE">
+            <LinearLayout
+                style="@style/TableCell.Start"
+                android:layout_width="65dp">
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:padding="3dip"
+                    android:text="State"
+                    android:textStyle="bold" />
+            </LinearLayout>
+
+            <RelativeLayout style="@style/TableCell.Inner">
+                <ImageView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_centerInParent="true"
+                    android:src="@drawable/screen_on_24"
+                    android:tint="@color/battery_consumer_slice_icon" />
+            </RelativeLayout>
+
+            <RelativeLayout style="@style/TableCell.Inner">
+                <ImageView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_centerInParent="true"
+                    android:src="@drawable/screen_off_24"
+                    android:tint="@color/battery_consumer_slice_icon" />
+            </RelativeLayout>
+
+            <RelativeLayout style="@style/TableCell.Inner">
+                <ImageView
+                    android:id="@+id/screen_on_24_icon"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_centerInParent="true"
+                    android:src="@drawable/screen_on_24"
+                    android:tint="@color/battery_consumer_slice_icon" />
+                <ImageView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_toRightOf="@id/screen_on_24_icon"
+                    android:src="@drawable/power_other_24"
+                    android:tint="@color/battery_consumer_slice_icon" />
+            </RelativeLayout>
+
+            <RelativeLayout style="@style/TableCell.End">
+                <ImageView
+                    android:id="@+id/screen_off_24_icon"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_centerInParent="true"
+                    android:src="@drawable/screen_off_24"
+                    android:tint="@color/battery_consumer_slice_icon" />
+                <ImageView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_toRightOf="@id/screen_off_24_icon"
+                    android:src="@drawable/power_other_24"
+                    android:tint="@color/battery_consumer_slice_icon" />
+            </RelativeLayout>
+        </TableRow>
+
+        <View
+            android:layout_height="1dip"
+            android:background="#000000" />
+    </TableLayout>
 </LinearLayout>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_picker_layout.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_picker_layout.xml
index 987de6b..b88425a 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_picker_layout.xml
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_picker_layout.xml
@@ -14,16 +14,30 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/swipe_refresh"
-    android:paddingTop="?attr/actionBarSize"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:fitsSystemWindows="true">
 
-    <androidx.recyclerview.widget.RecyclerView
-        android:id="@+id/list_view"
+    <androidx.appcompat.widget.Toolbar
+        android:id="@+id/toolbar"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"/>
+        android:layout_height="?attr/actionBarSize"
+        android:background="?attr/colorPrimary"
+        android:elevation="4dp"
+        android:theme="@style/ThemeOverlay.AppCompat.ActionBar" />
 
-</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
+    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+        android:id="@+id/swipe_refresh"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1">
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/list_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+
+    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
+</LinearLayout>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_slices_layout.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_slices_layout.xml
new file mode 100644
index 0000000..642c0de
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_slices_layout.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ 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.
+  -->
+
+<TableRow xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <LinearLayout style="@style/TableCell.Start">
+        <TextView
+            android:id="@+id/procState"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+    </LinearLayout>
+
+    <LinearLayout
+        style="@style/TableCell.Inner"
+        android:orientation="vertical">
+        <TextView
+            android:id="@+id/power_b_on"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="right" />
+        <TextView
+            android:id="@+id/duration_b_on"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="right" />
+    </LinearLayout>
+
+    <LinearLayout
+        style="@style/TableCell.Inner"
+        android:orientation="vertical">
+        <TextView
+            android:id="@+id/power_b_off"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="right" />
+        <TextView
+            android:id="@+id/duration_b_off"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="right" />
+    </LinearLayout>
+
+    <LinearLayout
+        style="@style/TableCell.Inner"
+        android:orientation="vertical">
+        <TextView
+            android:id="@+id/power_c_on"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="right" />
+        <TextView
+            android:id="@+id/duration_c_on"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="right" />
+    </LinearLayout>
+
+    <LinearLayout
+        style="@style/TableCell.End"
+        android:orientation="vertical">
+        <TextView
+            android:id="@+id/power_c_off"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="right" />
+        <TextView
+            android:id="@+id/duration_c_off"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="right" />
+    </LinearLayout>
+</TableRow>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml
index 2d276a5..46d8f04 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml
@@ -17,13 +17,12 @@
 <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/swipe_refresh"
-    android:paddingTop="?attr/actionBarSize"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:fitsSystemWindows="true">
 
     <LinearLayout
         android:orientation="vertical"
-        android:paddingTop="?attr/actionBarSize"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/values/colors.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/values/colors.xml
index 6cc70bd..1dc288a 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/res/values/colors.xml
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/values/colors.xml
@@ -18,4 +18,5 @@
 <resources>
     <color name="battery_consumer_bg_power_profile">#ffffff</color>
     <color name="battery_consumer_bg_energy_consumption">#fff5eb</color>
+    <color name="battery_consumer_slice_icon">#aaaaaa</color>
 </resources>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/values/styles.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/values/styles.xml
index fa30b2c..a298cc9 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/res/values/styles.xml
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/values/styles.xml
@@ -17,11 +17,9 @@
   -->
 
 <resources>
-    <style name="Theme" parent="Theme.MaterialComponents.Light">
+    <style name="Theme" parent="Theme.MaterialComponents.Light.NoActionBar">
         <item name="colorPrimary">#34a853</item>
-        <item name="android:windowActionBar">true</item>
-        <item name="android:windowNoTitle">false</item>
-        <item name="android:windowDrawsSystemBarBackgrounds">false</item>
+        <item name="toolbarStyle">@style/Widget.AppCompat.Toolbar</item>
     </style>
 
     <style name="LoadTestCardView" parent="Widget.MaterialComponents.CardView">
@@ -32,4 +30,25 @@
         <item name="android:textColor">#000000</item>
         <item name="android:textSize">18sp</item>
     </style>
-</resources>
\ No newline at end of file
+
+    <style name="TableCell">
+        <item name="android:layout_height">match_parent</item>
+        <item name="android:padding">4dp</item>
+    </style>
+
+    <style name="TableCell.Start" parent="TableCell">
+        <item name="android:background">@drawable/border_ltr</item>
+    </style>
+
+    <style name="TableCell.Inner" parent="TableCell">
+        <item name="android:background">@drawable/border_tr</item>
+        <item name="android:layout_width">0dp</item>
+        <item name="android:layout_weight">1</item>
+    </style>
+
+    <style name="TableCell.End" parent="TableCell">
+        <item name="android:background">@drawable/border_tr</item>
+        <item name="android:layout_width">0dp</item>
+        <item name="android:layout_weight">1</item>
+    </style>
+</resources>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
index f691a1b..35175a7 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
@@ -31,22 +31,16 @@
     public static final String UID_BATTERY_CONSUMER_ID_PREFIX = "APP|";
     public static final String AGGREGATE_BATTERY_CONSUMER_ID = "SYS|";
 
-    enum EntryType {
-        UID_TOTAL_POWER,
-        UID_POWER_PROFILE,
-        UID_POWER_PROFILE_PROCESS_STATE,
-        UID_POWER_ENERGY_CONSUMPTION,
-        UID_POWER_ENERGY_PROCESS_STATE,
-        UID_POWER_CUSTOM,
-        UID_DURATION,
+    public enum EntryType {
         DEVICE_TOTAL_POWER,
-        DEVICE_POWER_MODELED,
+        DEVICE_POWER,
         DEVICE_POWER_ENERGY_CONSUMPTION,
         DEVICE_POWER_CUSTOM,
         DEVICE_DURATION,
+        UID,
     }
 
-    enum ConsumerType {
+    public enum ConsumerType {
         UID_BATTERY_CONSUMER,
         DEVICE_POWER_COMPONENT,
     }
@@ -56,34 +50,38 @@
         public String title;
         public double value1;
         public double value2;
+        public List<Slice> slices;
+    }
+
+    public static class Slice {
+        public int powerState;
+        public int screenState;
+        public int processState;
+        public double powerMah;
+        public long durationMs;
     }
 
     private BatteryConsumerInfoHelper.BatteryConsumerInfo mBatteryConsumerInfo;
     private final List<Entry> mEntries = new ArrayList<>();
 
     public BatteryConsumerData(Context context,
-            List<BatteryUsageStats> batteryUsageStatsList, String batteryConsumerId) {
+            BatteryUsageStats batteryUsageStats, String batteryConsumerId) {
         switch (getConsumerType(batteryConsumerId)) {
             case UID_BATTERY_CONSUMER:
-                populateForUidBatteryConsumer(context, batteryUsageStatsList, batteryConsumerId);
+                populateForUidBatteryConsumer(context, batteryUsageStats, batteryConsumerId);
                 break;
             case DEVICE_POWER_COMPONENT:
-                populateForAggregateBatteryConsumer(context, batteryUsageStatsList);
+                populateForAggregateBatteryConsumer(context, batteryUsageStats);
                 break;
         }
     }
 
-    private void populateForUidBatteryConsumer(
-            Context context, List<BatteryUsageStats> batteryUsageStatsList,
+    private void populateForUidBatteryConsumer(Context context, BatteryUsageStats batteryUsageStats,
             String batteryConsumerId) {
-        BatteryUsageStats batteryUsageStats = batteryUsageStatsList.get(0);
-        BatteryUsageStats modeledBatteryUsageStats = batteryUsageStatsList.get(1);
         BatteryConsumer requestedBatteryConsumer = getRequestedBatteryConsumer(batteryUsageStats,
                 batteryConsumerId);
-        BatteryConsumer requestedModeledBatteryConsumer = getRequestedBatteryConsumer(
-                modeledBatteryUsageStats, batteryConsumerId);
 
-        if (requestedBatteryConsumer == null || requestedModeledBatteryConsumer == null) {
+        if (requestedBatteryConsumer == null) {
             mBatteryConsumerInfo = null;
             return;
         }
@@ -92,118 +90,95 @@
                 batteryUsageStats, batteryConsumerId, context.getPackageManager());
 
         double[] totalPowerByComponentMah = new double[BatteryConsumer.POWER_COMPONENT_COUNT];
-        double[] totalModeledPowerByComponentMah =
-                new double[BatteryConsumer.POWER_COMPONENT_COUNT];
         long[] totalDurationByComponentMs = new long[BatteryConsumer.POWER_COMPONENT_COUNT];
-        final int customComponentCount =
-                requestedBatteryConsumer.getCustomPowerComponentCount();
+        final int customComponentCount = requestedBatteryConsumer.getCustomPowerComponentCount();
         double[] totalCustomPowerByComponentMah = new double[customComponentCount];
 
         computeTotalPower(batteryUsageStats, totalPowerByComponentMah);
-        computeTotalPower(modeledBatteryUsageStats, totalModeledPowerByComponentMah);
         computeTotalPowerForCustomComponent(batteryUsageStats, totalCustomPowerByComponentMah);
         computeTotalDuration(batteryUsageStats, totalDurationByComponentMs);
 
-        if (isPowerProfileModelsOnly(requestedBatteryConsumer)) {
-            addEntry("Consumed", EntryType.UID_TOTAL_POWER,
-                    requestedBatteryConsumer.getConsumedPower(),
-                    batteryUsageStats.getAggregateBatteryConsumer(
-                            BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS)
-                            .getConsumedPower());
-        } else {
-            addEntry("Consumed (PowerStats)", EntryType.UID_TOTAL_POWER,
-                    requestedBatteryConsumer.getConsumedPower(),
-                    batteryUsageStats.getAggregateBatteryConsumer(
-                            BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS)
-                            .getConsumedPower());
-            addEntry("Consumed (PowerProfile)", EntryType.UID_TOTAL_POWER,
-                    requestedModeledBatteryConsumer.getConsumedPower(),
-                    modeledBatteryUsageStats.getAggregateBatteryConsumer(
-                            BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS)
-                            .getConsumedPower());
+        Entry totalsEntry = addEntry("Consumed", EntryType.UID,
+                requestedBatteryConsumer.getConsumedPower(),
+                batteryUsageStats.getAggregateBatteryConsumer(
+                                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS)
+                        .getConsumedPower());
+        addSlices(totalsEntry, requestedBatteryConsumer, BatteryConsumer.POWER_COMPONENT_BASE);
+        for (Slice slice : totalsEntry.slices) {
+            slice.powerMah = requestedBatteryConsumer.getConsumedPower(
+                    new BatteryConsumer.Dimensions(BatteryConsumer.POWER_COMPONENT_ANY,
+                            slice.processState, slice.screenState, slice.powerState));
         }
 
         for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
+            if (component == BatteryConsumer.POWER_COMPONENT_BASE) {
+                continue;
+            }
             final String metricTitle = getPowerMetricTitle(component);
-            final int powerModel = requestedBatteryConsumer.getPowerModel(component);
-            if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE
-                    || powerModel == BatteryConsumer.POWER_MODEL_UNDEFINED) {
-                addEntry(metricTitle, EntryType.UID_POWER_PROFILE,
-                        requestedBatteryConsumer.getConsumedPower(component),
+            double consumedPower = requestedBatteryConsumer.getConsumedPower(component);
+            if (consumedPower != 0) {
+                Entry entry = addEntry(metricTitle, EntryType.UID, consumedPower,
                         totalPowerByComponentMah[component]);
-                addProcessStateEntries(metricTitle, EntryType.UID_POWER_PROFILE_PROCESS_STATE,
-                        requestedBatteryConsumer, component);
-            } else {
-                addEntry(metricTitle + " (PowerStats)", EntryType.UID_POWER_ENERGY_CONSUMPTION,
-                        requestedBatteryConsumer.getConsumedPower(component),
-                        totalPowerByComponentMah[component]);
-                addProcessStateEntries(metricTitle, EntryType.UID_POWER_ENERGY_PROCESS_STATE,
-                        requestedBatteryConsumer, component);
-                addEntry(metricTitle + " (PowerProfile)", EntryType.UID_POWER_PROFILE,
-                        requestedModeledBatteryConsumer.getConsumedPower(component),
-                        totalModeledPowerByComponentMah[component]);
-                addProcessStateEntries(metricTitle, EntryType.UID_POWER_PROFILE_PROCESS_STATE,
-                        requestedModeledBatteryConsumer, component);
+                addSlices(entry, requestedBatteryConsumer, component);
             }
         }
 
         for (int component = 0; component < customComponentCount; component++) {
-            final String name = requestedBatteryConsumer.getCustomPowerComponentName(
-                    BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component);
-            addEntry(name + " (PowerStats)", EntryType.UID_POWER_CUSTOM,
-                    requestedBatteryConsumer.getConsumedPowerForCustomComponent(
-                            BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component),
-                    totalCustomPowerByComponentMah[component]
-            );
-        }
-
-        for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
-            final String metricTitle = getTimeMetricTitle(component);
-            addEntry(metricTitle, EntryType.UID_DURATION,
-                    requestedBatteryConsumer.getUsageDurationMillis(component),
-                    totalDurationByComponentMs[component]
-            );
+            int componentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component;
+            final String name = requestedBatteryConsumer.getCustomPowerComponentName(componentId);
+            double consumedPower = requestedBatteryConsumer.getConsumedPower(componentId);
+            if (consumedPower != 0) {
+                Entry entry = addEntry(name, EntryType.UID, consumedPower,
+                        totalCustomPowerByComponentMah[component]);
+                addSlices(entry, requestedBatteryConsumer, componentId);
+            }
         }
 
         mBatteryConsumerInfo = BatteryConsumerInfoHelper.makeBatteryConsumerInfo(batteryUsageStats,
                 batteryConsumerId, context.getPackageManager());
     }
 
-    private void addProcessStateEntries(String metricTitle, EntryType entryType,
-            BatteryConsumer batteryConsumer, int component) {
+    private void addSlices(Entry entry, BatteryConsumer batteryConsumer, int component) {
         final BatteryConsumer.Key[] keys = batteryConsumer.getKeys(component);
         if (keys == null || keys.length <= 1) {
             return;
         }
 
+        boolean hasProcStateData = false;
         for (BatteryConsumer.Key key : keys) {
-            String label;
-            switch (key.processState) {
-                case BatteryConsumer.PROCESS_STATE_FOREGROUND:
-                    label = "foreground";
-                    break;
-                case BatteryConsumer.PROCESS_STATE_BACKGROUND:
-                    label = "background";
-                    break;
-                case BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE:
-                    label = "FGS";
-                    break;
-                case BatteryConsumer.PROCESS_STATE_CACHED:
-                    label = "cached";
-                    break;
-                default:
-                    continue;
+            if (key.processState != BatteryConsumer.PROCESS_STATE_UNSPECIFIED) {
+                hasProcStateData = true;
+                break;
             }
-            addEntry(metricTitle + " \u2022 " + label, entryType,
-                    batteryConsumer.getConsumedPower(key), 0);
         }
+
+        ArrayList<Slice> slices = new ArrayList<>();
+        for (BatteryConsumer.Key key : keys) {
+            if (hasProcStateData && key.processState == BatteryConsumer.PROCESS_STATE_UNSPECIFIED) {
+                continue;
+            }
+
+            double powerMah = batteryConsumer.getConsumedPower(key);
+            long durationMs = batteryConsumer.getUsageDurationMillis(key);
+
+            if (powerMah == 0 && durationMs == 0) {
+                continue;
+            }
+
+            Slice slice = new Slice();
+            slice.powerState = key.powerState;
+            slice.screenState = key.screenState;
+            slice.processState = key.processState;
+            slice.powerMah = powerMah;
+            slice.durationMs = durationMs;
+
+            slices.add(slice);
+        }
+        entry.slices = slices;
     }
 
     private void populateForAggregateBatteryConsumer(Context context,
-            List<BatteryUsageStats> batteryUsageStatsList) {
-        BatteryUsageStats batteryUsageStats = batteryUsageStatsList.get(0);
-        BatteryUsageStats modeledBatteryUsageStats = batteryUsageStatsList.get(1);
-
+            BatteryUsageStats batteryUsageStats) {
         final BatteryConsumer deviceBatteryConsumer =
                 batteryUsageStats.getAggregateBatteryConsumer(
                         BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
@@ -211,46 +186,18 @@
                 batteryUsageStats.getAggregateBatteryConsumer(
                         BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS);
 
-        BatteryConsumer modeledDeviceBatteryConsumer =
-                modeledBatteryUsageStats.getAggregateBatteryConsumer(
-                        BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
-        BatteryConsumer modeledAppsBatteryConsumer =
-                modeledBatteryUsageStats.getAggregateBatteryConsumer(
-                        BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS);
-
-        if (isPowerProfileModelsOnly(deviceBatteryConsumer)) {
-            addEntry("Consumed", EntryType.DEVICE_TOTAL_POWER,
-                    deviceBatteryConsumer.getConsumedPower(),
-                    appsBatteryConsumer.getConsumedPower());
-        } else {
-            addEntry("Consumed (PowerStats)", EntryType.DEVICE_TOTAL_POWER,
-                    deviceBatteryConsumer.getConsumedPower(),
-                    appsBatteryConsumer.getConsumedPower());
-            addEntry("Consumed (PowerProfile)", EntryType.DEVICE_TOTAL_POWER,
-                    modeledDeviceBatteryConsumer.getConsumedPower(),
-                    modeledAppsBatteryConsumer.getConsumedPower());
-        }
+        addEntry("Consumed", EntryType.DEVICE_TOTAL_POWER,
+                deviceBatteryConsumer.getConsumedPower(),
+                appsBatteryConsumer.getConsumedPower());
 
         mBatteryConsumerInfo = BatteryConsumerInfoHelper.makeBatteryConsumerInfo(batteryUsageStats,
                 AGGREGATE_BATTERY_CONSUMER_ID, context.getPackageManager());
 
-
         for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
             final String metricTitle = getPowerMetricTitle(component);
-            final int powerModel = deviceBatteryConsumer.getPowerModel(component);
-            if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE
-                    || powerModel == BatteryConsumer.POWER_MODEL_UNDEFINED) {
-                addEntry(metricTitle, EntryType.DEVICE_POWER_MODELED,
-                        deviceBatteryConsumer.getConsumedPower(component),
-                        appsBatteryConsumer.getConsumedPower(component));
-            } else {
-                addEntry(metricTitle + " (PowerStats)", EntryType.DEVICE_POWER_ENERGY_CONSUMPTION,
-                        deviceBatteryConsumer.getConsumedPower(component),
-                        appsBatteryConsumer.getConsumedPower(component));
-                addEntry(metricTitle + " (PowerProfile)", EntryType.DEVICE_POWER_MODELED,
-                        modeledDeviceBatteryConsumer.getConsumedPower(component),
-                        modeledAppsBatteryConsumer.getConsumedPower(component));
-            }
+            addEntry(metricTitle, EntryType.DEVICE_POWER,
+                    deviceBatteryConsumer.getConsumedPower(component),
+                    appsBatteryConsumer.getConsumedPower(component));
         }
 
         final int customComponentCount =
@@ -258,10 +205,10 @@
         for (int component = 0; component < customComponentCount; component++) {
             final String name = deviceBatteryConsumer.getCustomPowerComponentName(
                     BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component);
-            addEntry(name + " (PowerStats)", EntryType.DEVICE_POWER_CUSTOM,
-                    deviceBatteryConsumer.getConsumedPowerForCustomComponent(
+            addEntry(name, EntryType.DEVICE_POWER_CUSTOM,
+                    deviceBatteryConsumer.getConsumedPower(
                             BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component),
-                    appsBatteryConsumer.getConsumedPowerForCustomComponent(
+                    appsBatteryConsumer.getConsumedPower(
                             BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component));
         }
 
@@ -272,17 +219,6 @@
         }
     }
 
-    private boolean isPowerProfileModelsOnly(BatteryConsumer batteryConsumer) {
-        for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
-            final int powerModel = batteryConsumer.getPowerModel(component);
-            if (powerModel != BatteryConsumer.POWER_MODEL_POWER_PROFILE
-                    && powerModel != BatteryConsumer.POWER_MODEL_UNDEFINED) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     private BatteryConsumer getRequestedBatteryConsumer(BatteryUsageStats batteryUsageStats,
             String batteryConsumerId) {
         for (UidBatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) {
@@ -352,13 +288,14 @@
         }
     }
 
-    private void addEntry(String title, EntryType entryType, double value1, double value2) {
+    private Entry addEntry(String title, EntryType entryType, double value1, double value2) {
         Entry entry = new Entry();
         entry.title = title;
         entry.entryType = entryType;
         entry.value1 = value1;
         entry.value2 = value2;
         mEntries.add(entry);
+        return entry;
     }
 
     public BatteryConsumerInfoHelper.BatteryConsumerInfo getBatteryConsumerInfo() {
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java
index c6d71c3..37d6b17 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java
@@ -24,6 +24,8 @@
 
 import androidx.annotation.NonNull;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
 import java.util.List;
 
 class BatteryConsumerInfoHelper {
@@ -76,6 +78,8 @@
         String packageWithHighestDrain = uidBatteryConsumer.getPackageWithHighestDrain();
         if (uid == Process.ROOT_UID) {
             info.label = "<root>";
+        } else if (uid < Process.FIRST_APPLICATION_UID) {
+            info.label = makeSystemUidLabel(uid);
         } else {
             String[] packages = packageManager.getPackagesForUid(uid);
             String primaryPackageName = null;
@@ -134,6 +138,23 @@
         return info;
     }
 
+    private static CharSequence makeSystemUidLabel(int uid) {
+        for (Field field : Process.class.getDeclaredFields()) {
+            final int modifiers = field.getModifiers();
+            if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)
+                    && field.getType().equals(int.class) && field.getName().endsWith("_UID")) {
+                try {
+                    if (uid == field.getInt(null)) {
+                        String label = field.getName();
+                        return label.substring(0, label.lastIndexOf("_UID"));
+                    }
+                } catch (IllegalAccessException ignored) {
+                }
+            }
+        }
+        return null;
+    }
+
     private static BatteryConsumerInfo makeAggregateBatteryConsumerInfo(
             BatteryUsageStats batteryUsageStats) {
         BatteryConsumerInfo info = new BatteryConsumerInfo();
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerActivity.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerActivity.java
index 4469168..3699690 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerActivity.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerActivity.java
@@ -30,8 +30,8 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
-import androidx.activity.ComponentActivity;
 import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
 import androidx.loader.app.LoaderManager;
 import androidx.loader.content.Loader;
 import androidx.recyclerview.widget.LinearLayoutManager;
@@ -50,7 +50,7 @@
  * Picker, showing a sorted lists of applications and other types of entities consuming power.
  * Opens BatteryStatsViewerActivity upon item selection.
  */
-public class BatteryConsumerPickerActivity extends ComponentActivity {
+public class BatteryConsumerPickerActivity extends AppCompatActivity {
     private static final String PREF_SELECTED_BATTERY_CONSUMER = "batteryConsumerId";
     private static final int BATTERY_STATS_REFRESH_RATE_MILLIS = 60 * 1000;
     private static final String FORCE_FRESH_STATS = "force_fresh_stats";
@@ -68,6 +68,7 @@
         super.onCreate(icicle);
 
         setContentView(R.layout.battery_consumer_picker_layout);
+        setSupportActionBar(findViewById(R.id.toolbar));
 
         mSwipeRefreshLayout = findViewById(R.id.swipe_refresh);
         mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_green_light);
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java
index e165c49..35021316 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java
@@ -17,14 +17,18 @@
 package com.android.frameworks.core.batterystatsviewer;
 
 import android.content.Context;
+import android.os.BatteryConsumer;
 import android.os.BatteryStatsManager;
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
 import android.os.Bundle;
+import android.util.SparseArray;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
+import android.widget.TableLayout;
+import android.widget.TableRow;
 import android.widget.TextView;
 import android.widget.Toast;
 
@@ -40,6 +44,7 @@
 
 import com.android.settingslib.utils.AsyncLoaderCompat;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
@@ -63,7 +68,16 @@
     private SwipeRefreshLayout mSwipeRefreshLayout;
     private View mCardView;
     private View mEmptyView;
-    private List<BatteryUsageStats> mBatteryUsageStats;
+    private BatteryUsageStats mBatteryUsageStats;
+
+    private static SparseArray<String> sProcStateNames = new SparseArray<>();
+    static {
+        sProcStateNames.put(BatteryConsumer.PROCESS_STATE_UNSPECIFIED, "-");
+        sProcStateNames.put(BatteryConsumer.PROCESS_STATE_FOREGROUND, "FG");
+        sProcStateNames.put(BatteryConsumer.PROCESS_STATE_BACKGROUND, "BG");
+        sProcStateNames.put(BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE, "FGS");
+        sProcStateNames.put(BatteryConsumer.PROCESS_STATE_CACHED, "Cached");
+    }
 
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -122,7 +136,7 @@
     }
 
     private static class BatteryUsageStatsLoader extends
-            AsyncLoaderCompat<List<BatteryUsageStats>> {
+            AsyncLoaderCompat<BatteryUsageStats> {
         private final BatteryStatsManager mBatteryStatsManager;
         private final boolean mForceFreshStats;
 
@@ -133,51 +147,44 @@
         }
 
         @Override
-        public List<BatteryUsageStats> loadInBackground() {
+        public BatteryUsageStats loadInBackground() {
             final int maxStatsAgeMs = mForceFreshStats ? 0 : BATTERY_STATS_REFRESH_RATE_MILLIS;
             final BatteryUsageStatsQuery queryDefault =
                     new BatteryUsageStatsQuery.Builder()
-                            .includePowerModels()
                             .includeProcessStateData()
+                            .includeScreenStateData()
+                            .includePowerStateData()
                             .setMaxStatsAgeMs(maxStatsAgeMs)
                             .build();
-            final BatteryUsageStatsQuery queryPowerProfileModeledOnly =
-                    new BatteryUsageStatsQuery.Builder()
-                            .powerProfileModeledOnly()
-                            .includePowerModels()
-                            .includeProcessStateData()
-                            .setMaxStatsAgeMs(maxStatsAgeMs)
-                            .build();
-            return mBatteryStatsManager.getBatteryUsageStats(
-                    List.of(queryDefault, queryPowerProfileModeledOnly));
+            return mBatteryStatsManager.getBatteryUsageStats(queryDefault);
         }
 
         @Override
-        protected void onDiscardResult(List<BatteryUsageStats> result) {
+        protected void onDiscardResult(BatteryUsageStats result) {
         }
     }
 
     private class BatteryUsageStatsLoaderCallbacks
-            implements LoaderCallbacks<List<BatteryUsageStats>> {
+            implements LoaderCallbacks<BatteryUsageStats> {
         @NonNull
         @Override
-        public Loader<List<BatteryUsageStats>> onCreateLoader(int id, Bundle args) {
+        public Loader<BatteryUsageStats> onCreateLoader(int id, Bundle args) {
             return new BatteryUsageStatsLoader(BatteryStatsViewerActivity.this,
                     args.getBoolean(FORCE_FRESH_STATS));
         }
 
         @Override
-        public void onLoadFinished(@NonNull Loader<List<BatteryUsageStats>> loader,
-                List<BatteryUsageStats> batteryUsageStats) {
+        public void onLoadFinished(@NonNull Loader<BatteryUsageStats> loader,
+                BatteryUsageStats batteryUsageStats) {
             onBatteryUsageStatsLoaded(batteryUsageStats);
         }
 
         @Override
-        public void onLoaderReset(@NonNull Loader<List<BatteryUsageStats>> loader) {
+        public void onLoaderReset(@NonNull Loader<BatteryUsageStats> loader) {
         }
     }
 
-    private void onBatteryUsageStatsLoaded(List<BatteryUsageStats> batteryUsageStats) {
+    private void onBatteryUsageStatsLoaded(BatteryUsageStats batteryUsageStats) {
         mBatteryUsageStats = batteryUsageStats;
         onBatteryStatsDataLoaded();
     }
@@ -238,10 +245,21 @@
     private static class BatteryStatsDataAdapter extends
             RecyclerView.Adapter<BatteryStatsDataAdapter.ViewHolder> {
         public static class ViewHolder extends RecyclerView.ViewHolder {
+            public static class SliceViewHolder {
+                public TableRow tableRow;
+                public int procState;
+                public int powerState;
+                public int screenState;
+                public TextView powerTextView;
+                public TextView durationTextView;
+            }
+
             public ImageView iconImageView;
             public TextView titleTextView;
             public TextView value1TextView;
             public TextView value2TextView;
+            public TableLayout table;
+            public List<SliceViewHolder> slices = new ArrayList<>();
 
             ViewHolder(View itemView) {
                 super(itemView);
@@ -250,6 +268,40 @@
                 titleTextView = itemView.findViewById(R.id.title);
                 value1TextView = itemView.findViewById(R.id.value1);
                 value2TextView = itemView.findViewById(R.id.value2);
+                table = itemView.findViewById(R.id.table);
+
+                for (int i = 0; i < sProcStateNames.size(); i++) {
+                    int procState = sProcStateNames.keyAt(i);
+                    slices.add(createSliceViewHolder(procState,
+                            BatteryConsumer.POWER_STATE_BATTERY,
+                            BatteryConsumer.SCREEN_STATE_ON,
+                            R.id.power_b_on, R.id.duration_b_on));
+                    slices.add(createSliceViewHolder(procState,
+                            BatteryConsumer.POWER_STATE_BATTERY,
+                            BatteryConsumer.SCREEN_STATE_OTHER,
+                            R.id.power_b_off, R.id.duration_b_off));
+                    slices.add(createSliceViewHolder(procState,
+                            BatteryConsumer.POWER_STATE_OTHER,
+                            BatteryConsumer.SCREEN_STATE_ON,
+                            R.id.power_c_on, R.id.duration_c_on));
+                    slices.add(createSliceViewHolder(procState,
+                            BatteryConsumer.POWER_STATE_OTHER,
+                            BatteryConsumer.SCREEN_STATE_OTHER,
+                            R.id.power_c_off, R.id.duration_c_off));
+                }
+            }
+
+            private SliceViewHolder createSliceViewHolder(int procState, int powerState,
+                    int screenState, int powerTextViewResId, int durationTextViewResId) {
+                TableRow powerRow = table.findViewWithTag("procstate" + procState);
+                SliceViewHolder svh = new SliceViewHolder();
+                svh.tableRow = powerRow;
+                svh.procState = procState;
+                svh.powerState = powerState;
+                svh.screenState = screenState;
+                svh.powerTextView = powerRow.findViewById(powerTextViewResId);
+                svh.durationTextView = powerRow.findViewById(durationTextViewResId);
+                return svh;
             }
         }
 
@@ -269,62 +321,32 @@
         @Override
         public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int position) {
             LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
-            View itemView = layoutInflater.inflate(R.layout.battery_consumer_entry_layout, parent,
-                    false);
+            ViewGroup itemView = (ViewGroup) layoutInflater.inflate(
+                    R.layout.battery_consumer_entry_layout, parent, false);
+            TableLayout table = itemView.findViewById(R.id.table);
+            int offset = 1;     // Skip header
+            for (int i = 0; i < sProcStateNames.size(); i++) {
+                View powerRow = layoutInflater.inflate(R.layout.battery_consumer_slices_layout,
+                        itemView, false);
+                ((TextView) powerRow.findViewById(R.id.procState))
+                        .setText(sProcStateNames.valueAt(i));
+                powerRow.setTag("procstate" + sProcStateNames.keyAt(i));
+                table.addView(powerRow, offset++);
+            }
+
             return new ViewHolder(itemView);
         }
 
         @Override
         public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
             BatteryConsumerData.Entry entry = mEntries.get(position);
-
             switch (entry.entryType) {
-                case UID_TOTAL_POWER:
+                case UID:
                     setTitleIconAndBackground(viewHolder, entry.title,
-                            R.drawable.gm_sum_24, 0);
+                            R.drawable.gm_energy_24, 0);
                     setPowerText(viewHolder.value1TextView, entry.value1);
                     setProportionText(viewHolder.value2TextView, entry);
-                    break;
-                case UID_POWER_PROFILE:
-                    setTitleIconAndBackground(viewHolder, entry.title,
-                            R.drawable.gm_calculate_24,
-                            R.color.battery_consumer_bg_power_profile);
-                    setPowerText(viewHolder.value1TextView, entry.value1);
-                    setProportionText(viewHolder.value2TextView, entry);
-                    break;
-                case UID_POWER_PROFILE_PROCESS_STATE:
-                    setTitleIconAndBackground(viewHolder, "    " + entry.title,
-                            R.drawable.gm_calculate_24,
-                            R.color.battery_consumer_bg_power_profile);
-                    setPowerText(viewHolder.value1TextView, entry.value1);
-                    viewHolder.value2TextView.setVisibility(View.INVISIBLE);
-                    break;
-                case UID_POWER_ENERGY_CONSUMPTION:
-                    setTitleIconAndBackground(viewHolder, entry.title,
-                            R.drawable.gm_energy_24,
-                            R.color.battery_consumer_bg_energy_consumption);
-                    setPowerText(viewHolder.value1TextView, entry.value1);
-                    setProportionText(viewHolder.value2TextView, entry);
-                    break;
-                case UID_POWER_ENERGY_PROCESS_STATE:
-                    setTitleIconAndBackground(viewHolder, "    " + entry.title,
-                            R.drawable.gm_energy_24,
-                            R.color.battery_consumer_bg_energy_consumption);
-                    setPowerText(viewHolder.value1TextView, entry.value1);
-                    viewHolder.value2TextView.setVisibility(View.INVISIBLE);
-                    break;
-                case UID_POWER_CUSTOM:
-                    setTitleIconAndBackground(viewHolder, entry.title,
-                            R.drawable.gm_energy_24,
-                            R.color.battery_consumer_bg_energy_consumption);
-                    setPowerText(viewHolder.value1TextView, entry.value1);
-                    setProportionText(viewHolder.value2TextView, entry);
-                    break;
-                case UID_DURATION:
-                    setTitleIconAndBackground(viewHolder, entry.title,
-                            R.drawable.gm_timer_24, 0);
-                    setDurationText(viewHolder.value1TextView, (long) entry.value1);
-                    setProportionText(viewHolder.value2TextView, entry);
+                    bindSlices(viewHolder, entry);
                     break;
                 case DEVICE_TOTAL_POWER:
                     setTitleIconAndBackground(viewHolder, entry.title,
@@ -332,27 +354,13 @@
                     setPowerText(viewHolder.value1TextView, entry.value1);
                     setPowerText(viewHolder.value2TextView, entry.value2);
                     break;
-                case DEVICE_POWER_MODELED:
+                case DEVICE_POWER:
                     setTitleIconAndBackground(viewHolder, entry.title,
                             R.drawable.gm_calculate_24,
                             R.color.battery_consumer_bg_power_profile);
                     setPowerText(viewHolder.value1TextView, entry.value1);
                     setPowerText(viewHolder.value2TextView, entry.value2);
                     break;
-                case DEVICE_POWER_ENERGY_CONSUMPTION:
-                    setTitleIconAndBackground(viewHolder, entry.title,
-                            R.drawable.gm_energy_24,
-                            R.color.battery_consumer_bg_energy_consumption);
-                    setPowerText(viewHolder.value1TextView, entry.value1);
-                    setPowerText(viewHolder.value2TextView, entry.value2);
-                    break;
-                case DEVICE_POWER_CUSTOM:
-                    setTitleIconAndBackground(viewHolder, entry.title,
-                            R.drawable.gm_energy_24,
-                            R.color.battery_consumer_bg_energy_consumption);
-                    setPowerText(viewHolder.value1TextView, entry.value1);
-                    setPowerText(viewHolder.value2TextView, entry.value2);
-                    break;
                 case DEVICE_DURATION:
                     setTitleIconAndBackground(viewHolder, entry.title,
                             R.drawable.gm_timer_24, 0);
@@ -362,6 +370,65 @@
             }
         }
 
+        private void bindSlices(ViewHolder viewHolder, BatteryConsumerData.Entry entry) {
+            if (entry.slices == null || entry.slices.isEmpty()) {
+                viewHolder.table.setVisibility(View.GONE);
+                return;
+            }
+            viewHolder.table.setVisibility(View.VISIBLE);
+
+            boolean[] procStateRowPopulated =
+                    new boolean[BatteryConsumer.PROCESS_STATE_COUNT];
+            for (BatteryConsumerData.Slice s : entry.slices) {
+                if (s.powerMah != 0 || s.durationMs != 0) {
+                    procStateRowPopulated[s.processState] = true;
+                }
+            }
+
+            for (ViewHolder.SliceViewHolder sliceViewHolder : viewHolder.slices) {
+                BatteryConsumerData.Slice slice = null;
+                for (BatteryConsumerData.Slice s : entry.slices) {
+                    if (s.powerState == sliceViewHolder.powerState
+                            && s.screenState == sliceViewHolder.screenState
+                            && s.processState == sliceViewHolder.procState) {
+                        slice = s;
+                        break;
+                    }
+                }
+                if (!procStateRowPopulated[sliceViewHolder.procState]) {
+                    sliceViewHolder.tableRow.setVisibility(View.GONE);
+                } else {
+                    sliceViewHolder.tableRow.setVisibility(View.VISIBLE);
+
+                    if (slice != null && (slice.powerMah != 0 || slice.durationMs != 0)) {
+                        sliceViewHolder.powerTextView.setText(
+                                String.format(Locale.getDefault(), "%.1f", slice.powerMah));
+                    } else {
+                        sliceViewHolder.powerTextView.setText(null);
+                    }
+
+                    if (slice != null && slice.durationMs != 0) {
+                        sliceViewHolder.durationTextView.setVisibility(View.VISIBLE);
+                        String timeString;
+                        if (slice.durationMs < MILLIS_IN_MINUTE) {
+                            timeString = String.format(Locale.getDefault(), "%ds",
+                                    slice.durationMs / 1000);
+                        } else if (slice.durationMs < 60 * MILLIS_IN_MINUTE) {
+                            timeString = String.format(Locale.getDefault(), "%dm %ds",
+                                    slice.durationMs / MILLIS_IN_MINUTE,
+                                    (slice.durationMs % MILLIS_IN_MINUTE) / 1000);
+                        } else {
+                            timeString = String.format(Locale.getDefault(), "%dm",
+                                    slice.durationMs / MILLIS_IN_MINUTE);
+                        }
+                        sliceViewHolder.durationTextView.setText(timeString);
+                    } else {
+                        sliceViewHolder.durationTextView.setVisibility(View.GONE);
+                    }
+                }
+            }
+        }
+
         private void setTitleIconAndBackground(ViewHolder viewHolder, String title, int icon,
                 int background) {
             viewHolder.titleTextView.setText(title);
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/TrampolineActivity.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/TrampolineActivity.java
index b016488..412169e 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/TrampolineActivity.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/TrampolineActivity.java
@@ -42,5 +42,6 @@
 
     private void launchMainActivity() {
         startActivity(new Intent(this, BatteryConsumerPickerActivity.class));
+        finish();
     }
 }
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index f39508d..4942557 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -152,6 +152,7 @@
         ":HelloWorldUsingSdkMalformedNegativeVersion",
         ":CtsStaticSharedLibConsumerApp1",
         ":CtsStaticSharedLibConsumerApp3",
+        ":CtsStaticSharedLibProviderApp1",
     ],
 }
 
diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml
index 5d8ff87..bada751 100644
--- a/core/tests/coretests/AndroidTest.xml
+++ b/core/tests/coretests/AndroidTest.xml
@@ -43,6 +43,8 @@
             value="/data/local/tmp/tests/coretests/pm/CtsStaticSharedLibConsumerApp1.apk"/>
         <option name="push-file" key="CtsStaticSharedLibConsumerApp3.apk"
             value="/data/local/tmp/tests/coretests/pm/CtsStaticSharedLibConsumerApp3.apk"/>
+        <option name="push-file" key="CtsStaticSharedLibProviderApp1.apk"
+                value="/data/local/tmp/tests/coretests/pm/CtsStaticSharedLibProviderApp1.apk"/>
     </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 23a0985..63e678d 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -467,7 +467,6 @@
                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
                 .setColor(Color.WHITE)
                 .setColorized(true)
-                .setFlag(FLAG_CAN_COLORIZE, true)
                 .build();
         assertThat(n.hasPromotableCharacteristics()).isTrue();
     }
@@ -481,7 +480,6 @@
                 .setContentTitle("TITLE")
                 .setColor(Color.WHITE)
                 .setColorized(true)
-                .setFlag(FLAG_CAN_COLORIZE, true)
                 .build();
         assertThat(n.hasPromotableCharacteristics()).isFalse();
     }
@@ -505,7 +503,20 @@
                 .setStyle(new Notification.BigTextStyle())
                 .setColor(Color.WHITE)
                 .setColorized(true)
-                .setFlag(FLAG_CAN_COLORIZE, true)
+                .build();
+        assertThat(n.hasPromotableCharacteristics()).isFalse();
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
+    public void testHasPromotableCharacteristics_groupSummary() {
+        Notification n = new Notification.Builder(mContext, "test")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
+                .setColor(Color.WHITE)
+                .setColorized(true)
+                .setGroup("someGroup")
+                .setGroupSummary(true)
                 .build();
         assertThat(n.hasPromotableCharacteristics()).isFalse();
     }
diff --git a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
index 2fc72e1..177c7f0 100644
--- a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
+++ b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
@@ -26,6 +26,7 @@
 import static com.android.internal.os.Flags.FLAG_APPLICATION_SHARED_MEMORY_ENABLED;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertSame;
@@ -34,6 +35,8 @@
 
 import android.annotation.SuppressLint;
 import android.app.PropertyInvalidatedCache.Args;
+import android.app.PropertyInvalidatedCache.NonceWatcher;
+import android.app.PropertyInvalidatedCache.NonceStore;
 import android.os.Binder;
 import com.android.internal.os.ApplicationSharedMemory;
 
@@ -45,11 +48,15 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.os.ApplicationSharedMemory;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 
+import java.util.concurrent.TimeUnit;
+
 /**
  * Test for verifying the behavior of {@link PropertyInvalidatedCache}.  This test does
  * not use any actual binder calls - it is entirely self-contained.  This test also relies
@@ -490,6 +497,62 @@
         }
     }
 
+    // Verify that NonceWatcher change reporting works properly
+    @Test
+    public void testNonceWatcherChanged() {
+        // Create a cache that will write a system nonce.
+        TestCache sysCache = new TestCache(MODULE_SYSTEM, "watcher1");
+        sysCache.testPropertyName();
+
+        try (NonceWatcher watcher1 = sysCache.getNonceWatcher()) {
+
+            // The property has never been invalidated so it is still unset.
+            assertFalse(watcher1.isChanged());
+
+            // Invalidate the cache.  The first call to isChanged will return true but the second
+            // call will return false;
+            sysCache.invalidateCache();
+            assertTrue(watcher1.isChanged());
+            assertFalse(watcher1.isChanged());
+
+            // Invalidate the cache.  The first call to isChanged will return true but the second
+            // call will return false;
+            sysCache.invalidateCache();
+            sysCache.invalidateCache();
+            assertTrue(watcher1.isChanged());
+            assertFalse(watcher1.isChanged());
+
+            NonceWatcher watcher2 = sysCache.getNonceWatcher();
+            // This watcher return isChanged() immediately because the nonce is not UNSET.
+            assertTrue(watcher2.isChanged());
+        }
+    }
+
+    // Verify that NonceWatcher wait-for-change works properly
+    @Test
+    public void testNonceWatcherWait() throws Exception {
+        // Create a cache that will write a system nonce.
+        TestCache sysCache = new TestCache(MODULE_TEST, "watcher1");
+
+        // Use the watcher outside a try-with-resources block.
+        NonceWatcher watcher1 = sysCache.getNonceWatcher();
+
+        // Invalidate the cache and then "wait".
+        sysCache.invalidateCache();
+        assertEquals(watcher1.waitForChange(), 1);
+
+        // Invalidate the cache three times and then "wait".
+        sysCache.invalidateCache();
+        sysCache.invalidateCache();
+        sysCache.invalidateCache();
+        assertEquals(watcher1.waitForChange(), 3);
+
+        // Wait for a change.  It won't happen, but the code will time out after 10ms.
+        assertEquals(watcher1.waitForChange(10, TimeUnit.MILLISECONDS), 0);
+
+        watcher1.close();
+    }
+
     // Verify the behavior of shared memory nonce storage.  This does not directly test the cache
     // storing nonces in shared memory.
     @RequiresFlagsEnabled(FLAG_APPLICATION_SHARED_MEMORY_ENABLED)
@@ -502,10 +565,8 @@
 
         // Create a server-side store and a client-side store.  The server's store is mutable and
         // the client's store is not mutable.
-        PropertyInvalidatedCache.NonceStore server =
-                new PropertyInvalidatedCache.NonceStore(shmem.getSystemNonceBlock(), true);
-        PropertyInvalidatedCache.NonceStore client =
-                new PropertyInvalidatedCache.NonceStore(shmem.getSystemNonceBlock(), false);
+        NonceStore server = new NonceStore(shmem.getSystemNonceBlock(), true);
+        NonceStore client = new NonceStore(shmem.getSystemNonceBlock(), false);
 
         final String name1 = "name1";
         assertEquals(server.getHandleForName(name1), INVALID_NONCE_INDEX);
diff --git a/core/tests/coretests/src/android/app/wallpaper/WallpaperDescriptionTest.java b/core/tests/coretests/src/android/app/wallpaper/WallpaperDescriptionTest.java
index 01c2abf..a22eae3 100644
--- a/core/tests/coretests/src/android/app/wallpaper/WallpaperDescriptionTest.java
+++ b/core/tests/coretests/src/android/app/wallpaper/WallpaperDescriptionTest.java
@@ -15,13 +15,20 @@
  */
 package android.app.wallpaper;
 
+import static android.app.WallpaperManager.ORIENTATION_LANDSCAPE;
+import static android.app.WallpaperManager.ORIENTATION_PORTRAIT;
+import static android.app.WallpaperManager.ORIENTATION_SQUARE_LANDSCAPE;
+import static android.app.WallpaperManager.ORIENTATION_SQUARE_PORTRAIT;
+
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.content.ComponentName;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.PersistableBundle;
+import android.util.SparseArray;
 import android.util.Xml;
 
 import com.android.modules.utils.TypedXmlPullParser;
@@ -41,17 +48,20 @@
 
 @RunWith(JUnit4.class)
 public class WallpaperDescriptionTest {
-    private static final String TAG = "WallpaperDescriptionTest";
+    private static final Rect DEFAULT_CROP_PORTRAIT = new Rect(1, 2, 3, 4);
+    private static final Rect DEFAULT_CROP_LANDSCAPE = new Rect(5, 6, 7, 8);
+    private static final Rect DEFAULT_CROP_SQUARE_PORTRAIT = new Rect(9, 10, 11, 12);
+    private static final Rect DEFAULT_CROP_SQUARE_LANDSCAPE = new Rect(13, 14, 15, 16);
 
     private final ComponentName mTestComponent = new ComponentName("fakePackage", "fakeClass");
 
     @Test
     public void equals_ignoresIrrelevantFields() {
         String id = "fakeId";
-        WallpaperDescription desc1 = new WallpaperDescription.Builder().setComponent(
-                mTestComponent).setId(id).setTitle("fake one").build();
-        WallpaperDescription desc2 = new WallpaperDescription.Builder().setComponent(
-                mTestComponent).setId(id).setTitle("fake different").build();
+        WallpaperDescription desc1 = new WallpaperDescription.Builder()
+                .setComponent(mTestComponent).setId(id).setTitle("fake one").build();
+        WallpaperDescription desc2 = new WallpaperDescription.Builder()
+                .setComponent(mTestComponent).setId(id).setTitle("fake different").build();
 
         assertThat(desc1).isEqualTo(desc2);
     }
@@ -72,13 +82,21 @@
         final Uri thumbnail = Uri.parse("http://www.bogus.com/thumbnail");
         final List<CharSequence> description = List.of("line1", "line2");
         final Uri contextUri = Uri.parse("http://www.bogus.com/contextUri");
-        final PersistableBundle content = new PersistableBundle();
-        content.putString("ckey", "cvalue");
+        final PersistableBundle content = makeDefaultContent();
+        final SparseArray<Rect> cropHints = makeDefaultCropHints();
+        final float sampleSize = 0.9f;
         WallpaperDescription source = new WallpaperDescription.Builder()
-                .setComponent(mTestComponent).setId("fakeId").setThumbnail(thumbnail)
-                .setTitle("Fake title").setDescription(description)
-                .setContextUri(contextUri).setContextDescription("Context description")
-                .setContent(content).build();
+                .setComponent(mTestComponent)
+                .setId("fakeId")
+                .setThumbnail(thumbnail)
+                .setTitle("Fake title")
+                .setDescription(description)
+                .setContextUri(contextUri)
+                .setContextDescription("Context description")
+                .setContent(content)
+                .setCropHints(cropHints)
+                .setSampleSize(sampleSize)
+                .build();
 
         ByteArrayOutputStream ostream = new ByteArrayOutputStream();
         TypedXmlSerializer serializer = Xml.newBinarySerializer();
@@ -122,6 +140,57 @@
         assertThat(destination.getContent()).isNotNull();
         assertThat(destination.getContent().getString("ckey")).isEqualTo(
                 source.getContent().getString("ckey"));
+        assertThat(destination.getCropHints()).isNotNull();
+        assertThat(destination.getCropHints().get(ORIENTATION_PORTRAIT)).isEqualTo(
+                DEFAULT_CROP_PORTRAIT);
+        assertThat(destination.getCropHints().get(ORIENTATION_LANDSCAPE)).isEqualTo(
+                DEFAULT_CROP_LANDSCAPE);
+        assertThat(destination.getCropHints().get(ORIENTATION_SQUARE_PORTRAIT)).isEqualTo(
+                DEFAULT_CROP_SQUARE_PORTRAIT);
+        assertThat(destination.getCropHints().get(ORIENTATION_SQUARE_LANDSCAPE)).isEqualTo(
+                DEFAULT_CROP_SQUARE_LANDSCAPE);
+        assertThat(destination.getSampleSize()).isEqualTo(sampleSize);
+    }
+
+    @Test
+    public void xml_roundTripSucceeds_withNulls() throws IOException, XmlPullParserException {
+        WallpaperDescription source = new WallpaperDescription.Builder().build();
+
+        ByteArrayOutputStream ostream = new ByteArrayOutputStream();
+        TypedXmlSerializer serializer = Xml.newBinarySerializer();
+        serializer.setOutput(ostream, StandardCharsets.UTF_8.name());
+        serializer.startDocument(null, true);
+        serializer.startTag(null, "test");
+        source.saveToXml(serializer);
+        serializer.endTag(null, "test");
+        serializer.endDocument();
+        ostream.close();
+
+        WallpaperDescription destination = null;
+        ByteArrayInputStream istream = new ByteArrayInputStream(ostream.toByteArray());
+        TypedXmlPullParser parser = Xml.newBinaryPullParser();
+        parser.setInput(istream, StandardCharsets.UTF_8.name());
+        int type;
+        do {
+            type = parser.next();
+            if (type == XmlPullParser.START_TAG && "test".equals(parser.getName())) {
+                destination = WallpaperDescription.restoreFromXml(parser);
+            }
+        } while (type != XmlPullParser.END_DOCUMENT);
+
+        assertThat(destination).isNotNull();
+        assertThat(destination.getComponent()).isEqualTo(source.getComponent());
+        assertThat(destination.getId()).isEqualTo(source.getId());
+        assertThat(destination.getThumbnail()).isEqualTo(source.getThumbnail());
+        assertThat(destination.getTitle()).isNull();
+        assertThat(destination.getDescription()).hasSize(0);
+        assertThat(destination.getContextUri()).isEqualTo(source.getContextUri());
+        assertThat(destination.getContextDescription()).isNull();
+        assertThat(destination.getContent()).isNotNull();
+        assertThat(destination.getContent().keySet()).isEmpty();
+        assertThat(destination.getCropHints()).isNotNull();
+        assertThat(destination.getCropHints().size()).isEqualTo(0);
+        assertThat(destination.getSampleSize()).isEqualTo(source.getSampleSize());
     }
 
     @Test
@@ -129,13 +198,21 @@
         final Uri thumbnail = Uri.parse("http://www.bogus.com/thumbnail");
         final List<CharSequence> description = List.of("line1", "line2");
         final Uri contextUri = Uri.parse("http://www.bogus.com/contextUri");
-        final PersistableBundle content = new PersistableBundle();
-        content.putString("ckey", "cvalue");
-        WallpaperDescription source = new WallpaperDescription.Builder().setComponent(
-                mTestComponent).setId("fakeId").setThumbnail(thumbnail).setTitle(
-                "Fake title").setDescription(description).setContextUri(
-                contextUri).setContextDescription("Context description").setContent(
-                content).build();
+        final PersistableBundle content = makeDefaultContent();
+        final SparseArray<Rect> cropHints = makeDefaultCropHints();
+        final float sampleSize = 0.9f;
+        WallpaperDescription source = new WallpaperDescription.Builder()
+                .setComponent(mTestComponent)
+                .setId("fakeId")
+                .setThumbnail(thumbnail)
+                .setTitle("Fake title")
+                .setDescription(description)
+                .setContextUri(contextUri)
+                .setContextDescription("Context description")
+                .setContent(content)
+                .setCropHints(cropHints)
+                .setSampleSize(sampleSize)
+                .build();
 
         Parcel parcel = Parcel.obtain();
         source.writeToParcel(parcel, 0);
@@ -162,6 +239,16 @@
         assertThat(destination.getContent()).isNotNull();
         assertThat(destination.getContent().getString("ckey")).isEqualTo(
                 source.getContent().getString("ckey"));
+        assertThat(destination.getCropHints()).isNotNull();
+        assertThat(destination.getCropHints().get(ORIENTATION_PORTRAIT)).isEqualTo(
+                DEFAULT_CROP_PORTRAIT);
+        assertThat(destination.getCropHints().get(ORIENTATION_LANDSCAPE)).isEqualTo(
+                DEFAULT_CROP_LANDSCAPE);
+        assertThat(destination.getCropHints().get(ORIENTATION_SQUARE_PORTRAIT)).isEqualTo(
+                DEFAULT_CROP_SQUARE_PORTRAIT);
+        assertThat(destination.getCropHints().get(ORIENTATION_SQUARE_LANDSCAPE)).isEqualTo(
+                DEFAULT_CROP_SQUARE_LANDSCAPE);
+        assertThat(destination.getSampleSize()).isEqualTo(sampleSize);
     }
 
     @Test
@@ -178,17 +265,14 @@
         assertThat(destination.getId()).isEqualTo(source.getId());
         assertThat(destination.getThumbnail()).isEqualTo(source.getThumbnail());
         assertThat(destination.getTitle()).isNull();
-        assertThat(destination.getDescription()).hasSize(source.getDescription().size());
-        for (int i = 0; i < destination.getDescription().size(); i++) {
-            CharSequence strDest = destination.getDescription().get(i);
-            CharSequence strSrc = source.getDescription().get(i);
-            assertWithMessage("description string mismatch")
-                    .that(CharSequence.compare(strDest, strSrc)).isEqualTo(0);
-        }
+        assertThat(destination.getDescription()).hasSize(0);
         assertThat(destination.getContextUri()).isEqualTo(source.getContextUri());
         assertThat(destination.getContextDescription()).isNull();
         assertThat(destination.getContent()).isNotNull();
         assertThat(destination.getContent().keySet()).isEmpty();
+        assertThat(destination.getCropHints()).isNotNull();
+        assertThat(destination.getCropHints().size()).isEqualTo(0);
+        assertThat(destination.getSampleSize()).isEqualTo(source.getSampleSize());
     }
 
     @Test
@@ -197,14 +281,22 @@
         final Uri thumbnail = Uri.parse("http://www.bogus.com/thumbnail");
         final List<CharSequence> description = List.of("line1", "line2");
         final Uri contextUri = Uri.parse("http://www.bogus.com/contextUri");
-        final PersistableBundle content = new PersistableBundle();
-        content.putString("ckey", "cvalue");
+        final PersistableBundle content = makeDefaultContent();
+        final SparseArray<Rect> cropHints = makeDefaultCropHints();
+        final float sampleSize = 1.1f;
         final String destinationId = "destinationId";
-        WallpaperDescription source = new WallpaperDescription.Builder().setComponent(
-                mTestComponent).setId(sourceId).setThumbnail(thumbnail).setTitle(
-                "Fake title").setDescription(description).setContextUri(
-                contextUri).setContextDescription("Context description").setContent(
-                content).build();
+        WallpaperDescription source = new WallpaperDescription.Builder()
+                .setComponent(mTestComponent)
+                .setId(sourceId)
+                .setThumbnail(thumbnail)
+                .setTitle("Fake title")
+                .setDescription(description)
+                .setContextUri(contextUri)
+                .setContextDescription("Context description")
+                .setContent(content)
+                .setCropHints(cropHints)
+                .setSampleSize(sampleSize)
+                .build();
 
         WallpaperDescription destination = source.toBuilder().setId(destinationId).build();
 
@@ -227,5 +319,29 @@
         assertThat(destination.getContent()).isNotNull();
         assertThat(destination.getContent().getString("ckey")).isEqualTo(
                 source.getContent().getString("ckey"));
+        assertThat(destination.getCropHints().get(ORIENTATION_PORTRAIT)).isEqualTo(
+                DEFAULT_CROP_PORTRAIT);
+        assertThat(destination.getCropHints().get(ORIENTATION_LANDSCAPE)).isEqualTo(
+                DEFAULT_CROP_LANDSCAPE);
+        assertThat(destination.getCropHints().get(ORIENTATION_SQUARE_PORTRAIT)).isEqualTo(
+                DEFAULT_CROP_SQUARE_PORTRAIT);
+        assertThat(destination.getCropHints().get(ORIENTATION_SQUARE_LANDSCAPE)).isEqualTo(
+                DEFAULT_CROP_SQUARE_LANDSCAPE);
+        assertThat(destination.getSampleSize()).isEqualTo(sampleSize);
+    }
+
+    private static PersistableBundle makeDefaultContent() {
+        final PersistableBundle content = new PersistableBundle();
+        content.putString("ckey", "cvalue");
+        return content;
+    }
+
+    private static SparseArray<Rect> makeDefaultCropHints() {
+        final SparseArray<Rect> cropHints = new SparseArray<>();
+        cropHints.put(ORIENTATION_PORTRAIT, DEFAULT_CROP_PORTRAIT);
+        cropHints.put(ORIENTATION_LANDSCAPE, DEFAULT_CROP_LANDSCAPE);
+        cropHints.put(ORIENTATION_SQUARE_PORTRAIT, DEFAULT_CROP_SQUARE_PORTRAIT);
+        cropHints.put(ORIENTATION_SQUARE_LANDSCAPE, DEFAULT_CROP_SQUARE_LANDSCAPE);
+        return cropHints;
     }
 }
diff --git a/core/tests/coretests/src/android/appwidget/AppWidgetEventsTest.kt b/core/tests/coretests/src/android/appwidget/AppWidgetEventsTest.kt
new file mode 100644
index 0000000..ea1158c
--- /dev/null
+++ b/core/tests/coretests/src/android/appwidget/AppWidgetEventsTest.kt
@@ -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 android.appwidget
+
+import android.graphics.Rect
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class AppWidgetEventsTest {
+    @Test
+    fun createWidgetInteractionEvent() {
+        val appWidgetId = 1
+        val durationMs = 1000L
+        val position = Rect(1, 2, 3, 4)
+        val clicked = intArrayOf(1, 2, 3)
+        val scrolled = intArrayOf(4, 5, 6)
+        val bundle = AppWidgetManager.createWidgetInteractionEvent(
+            appWidgetId,
+            durationMs,
+            position,
+            clicked,
+            scrolled
+        )
+
+        assertThat(bundle.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID)).isEqualTo(appWidgetId)
+        assertThat(bundle.getLong(AppWidgetManager.EXTRA_EVENT_DURATION_MS)).isEqualTo(durationMs)
+        assertThat(bundle.getIntArray(AppWidgetManager.EXTRA_EVENT_POSITION_RECT))
+            .asList().containsExactly(position.left, position.top, position.right, position.bottom)
+        assertThat(bundle.getIntArray(AppWidgetManager.EXTRA_EVENT_CLICKED_VIEWS))
+            .asList().containsExactly(clicked[0], clicked[1], clicked[2])
+        assertThat(bundle.getIntArray(AppWidgetManager.EXTRA_EVENT_SCROLLED_VIEWS))
+            .asList().containsExactly(scrolled[0], scrolled[1], scrolled[2])
+    }
+}
diff --git a/core/tests/coretests/src/android/appwidget/OWNERS b/core/tests/coretests/src/android/appwidget/OWNERS
new file mode 100644
index 0000000..d724cac
--- /dev/null
+++ b/core/tests/coretests/src/android/appwidget/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/appwidget/OWNERS
diff --git a/core/tests/coretests/src/android/content/IntentTest.java b/core/tests/coretests/src/android/content/IntentTest.java
index 7bc4abd..fdfb0c3 100644
--- a/core/tests/coretests/src/android/content/IntentTest.java
+++ b/core/tests/coretests/src/android/content/IntentTest.java
@@ -19,8 +19,9 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
-import android.net.Uri;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -29,6 +30,7 @@
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.security.Flags;
+import android.util.ArraySet;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
@@ -40,6 +42,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Set;
 
 /**
  *  Build/Install/Run:
@@ -51,7 +54,6 @@
 public class IntentTest {
     private static final String TEST_ACTION = "android.content.IntentTest_test";
     private static final String TEST_EXTRA_NAME = "testExtraName";
-    private static final Uri TEST_URI = Uri.parse("content://com.example/people");
 
     @Rule
     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@@ -129,4 +131,111 @@
         }
     }
 
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_PREVENT_INTENT_REDIRECT)
+    public void testFillInCreatorTokenInfo() {
+        // case 1: intent does not have creatorTokenInfo; fillinIntent contains creatorTokenInfo
+        Intent intent = new Intent();
+        Intent fillInIntent = new Intent();
+        fillInIntent.setCreatorToken(new Binder());
+        fillInIntent.putExtra("extraKey", new Intent());
+
+        fillInIntent.collectExtraIntentKeys();
+        intent.fillIn(fillInIntent, 0);
+
+        // extra intent keys are merged
+        assertThat(intent.getExtraIntentKeys()).isEqualTo(fillInIntent.getExtraIntentKeys());
+        // but creator token is not overwritten.
+        assertThat(intent.getCreatorToken()).isNull();
+
+
+        // case 2: Both intent and fillInIntent contains creatorToken, intent's creatorToken is not
+        // overwritten.
+        intent = new Intent();
+        IBinder creatorToken = new Binder();
+        intent.setCreatorToken(creatorToken);
+        fillInIntent = new Intent();
+        fillInIntent.setCreatorToken(new Binder());
+
+        intent.fillIn(fillInIntent, 0);
+
+        assertThat(intent.getCreatorToken()).isEqualTo(creatorToken);
+
+
+        // case 3: Contains duplicate extra keys
+        intent = new Intent();
+        intent.putExtra("key1", new Intent());
+        intent.putExtra("key2", new Intent());
+        fillInIntent = new Intent();
+        fillInIntent.putExtra("key1", new Intent());
+        fillInIntent.putExtra("key3", new Intent());
+
+        intent.collectExtraIntentKeys();
+        Set originalIntentKeys = new ArraySet<>(intent.getExtraIntentKeys());
+
+        fillInIntent.collectExtraIntentKeys();
+        intent.fillIn(fillInIntent, 0);
+
+        assertThat(intent.getExtraIntentKeys()).hasSize(3);
+        assertTrue(intent.getExtraIntentKeys().containsAll(originalIntentKeys));
+        assertTrue(intent.getExtraIntentKeys().containsAll(fillInIntent.getExtraIntentKeys()));
+
+
+        // case 4: Both contains a mixture of extras and clip data. NOT force to fill in clip data.
+        intent = new Intent();
+        ClipData clipData = ClipData.newIntent("clip", new Intent());
+        clipData.addItem(new ClipData.Item(new Intent()));
+        intent.setClipData(clipData);
+        intent.putExtra("key1", new Intent());
+        intent.putExtra("key2", new Intent());
+        fillInIntent = new Intent();
+        ClipData fillInClipData = ClipData.newIntent("clip", new Intent());
+        fillInClipData.addItem(new ClipData.Item(new Intent()));
+        fillInClipData.addItem(new ClipData.Item(new Intent()));
+        fillInIntent.setClipData(fillInClipData);
+        fillInIntent.putExtra("key1", new Intent());
+        fillInIntent.putExtra("key3", new Intent());
+
+        intent.collectExtraIntentKeys();
+        originalIntentKeys = new ArraySet<>(intent.getExtraIntentKeys());
+        fillInIntent.collectExtraIntentKeys();
+        intent.fillIn(fillInIntent, 0);
+
+        // size is 5 ( 3 extras merged from both + 2 clip data in the original.
+        assertThat(intent.getExtraIntentKeys()).hasSize(5);
+        // all keys from original are kept.
+        assertTrue(intent.getExtraIntentKeys().containsAll(originalIntentKeys));
+        // Not all keys from fillInIntent are kept - clip data keys are dropped.
+        assertFalse(intent.getExtraIntentKeys().containsAll(fillInIntent.getExtraIntentKeys()));
+
+
+        // case 5: Both contains a mixture of extras and clip data. Force to fill in clip data.
+        intent = new Intent();
+        clipData = ClipData.newIntent("clip", new Intent());
+        clipData.addItem(new ClipData.Item(new Intent()));
+        clipData.addItem(new ClipData.Item(new Intent()));
+        clipData.addItem(new ClipData.Item(new Intent()));
+        intent.setClipData(clipData);
+        intent.putExtra("key1", new Intent());
+        intent.putExtra("key2", new Intent());
+        fillInIntent = new Intent();
+        fillInClipData = ClipData.newIntent("clip", new Intent());
+        fillInClipData.addItem(new ClipData.Item(new Intent()));
+        fillInClipData.addItem(new ClipData.Item(new Intent()));
+        fillInIntent.setClipData(fillInClipData);
+        fillInIntent.putExtra("key1", new Intent());
+        fillInIntent.putExtra("key3", new Intent());
+
+        intent.collectExtraIntentKeys();
+        originalIntentKeys = new ArraySet<>(intent.getExtraIntentKeys());
+        fillInIntent.collectExtraIntentKeys();
+        intent.fillIn(fillInIntent, Intent.FILL_IN_CLIP_DATA);
+
+        // size is 6 ( 3 extras merged from both + 3 clip data in the fillInIntent.
+        assertThat(intent.getExtraIntentKeys()).hasSize(6);
+        // all keys from fillInIntent are kept.
+        assertTrue(intent.getExtraIntentKeys().containsAll(fillInIntent.getExtraIntentKeys()));
+        // Not all keys from intent are kept - clip data keys are dropped.
+        assertFalse(intent.getExtraIntentKeys().containsAll(originalIntentKeys));
+    }
 }
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTest.java b/core/tests/coretests/src/android/content/pm/PackageManagerTest.java
index b60d614..c55008e 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTest.java
@@ -24,6 +24,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class PackageManagerTest {
@@ -46,4 +49,25 @@
     public void testResolveInfoFlags() throws Exception {
         assertThat(PackageManager.ResolveInfoFlags.of(42L).getValue()).isEqualTo(42L);
     }
+
+    @Test
+    public void testSdkFeatureCount() throws Exception {
+        // Check to make sure the system feature `SdkConst` annotation processor yields sensible
+        // results. We don't care about the exactness, just that it's not pathologically wrong.
+        assertThat(PackageManager.SDK_FEATURE_COUNT).isGreaterThan(150);
+        assertThat(PackageManager.SDK_FEATURE_COUNT).isLessThan(500);
+        assertThat(PackageManager.SDK_FEATURE_COUNT)
+                .isWithin(50)
+                .of(getApproximateFeatureCountUsingReflection());
+    }
+
+    /* Return a ballpark estimate of the feature count using FEATURE_ field names. */
+    private static int getApproximateFeatureCountUsingReflection() {
+        return (int)
+                Arrays.stream(PackageManager.class.getFields())
+                        .filter(field -> Modifier.isStatic(field.getModifiers()))
+                        .filter(field -> Modifier.isFinal(field.getModifiers()))
+                        .filter(field -> field.getName().startsWith("FEATURE_"))
+                        .count();
+    }
 }
diff --git a/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java b/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java
index ecacdb2..6d2dd53 100644
--- a/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java
+++ b/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java
@@ -73,6 +73,7 @@
     private static final String TEST_APP_USING_SDK1_AND_SDK1 = "HelloWorldUsingSdk1AndSdk1.apk";
     private static final String TEST_APP_USING_SDK_MALFORMED_VERSION =
             "HelloWorldUsingSdkMalformedNegativeVersion.apk";
+    private static final String TEST_STATIC_LIB_APP = "CtsStaticSharedLibProviderApp1.apk";
     private static final String TEST_APP_USING_STATIC_LIB = "CtsStaticSharedLibConsumerApp1.apk";
     private static final String TEST_APP_USING_STATIC_LIB_TWO_CERTS =
             "CtsStaticSharedLibConsumerApp3.apk";
@@ -207,6 +208,17 @@
         assertThat(liteCerts).isEqualTo(pkgCerts);
     }
 
+    @Test
+    public void testParseApkLite_isIsStaticLibrary() throws Exception {
+        File apkFile = copyApkToTmpDir(TEST_STATIC_LIB_APP);
+        ParseResult<ApkLite> result = ApkLiteParseUtils
+                .parseApkLite(ParseTypeImpl.forDefaultParsing().reset(), apkFile, 0);
+        assertThat(result.isError()).isFalse();
+        ApkLite baseApk = result.getResult();
+
+        assertThat(baseApk.isIsStaticLibrary()).isTrue();
+    }
+
     @SuppressLint("CheckResult")
     @Test
     public void testParseApkLite_malformedUsesSdkLibrary_duplicate() throws Exception {
diff --git a/core/tests/coretests/src/android/os/BuildTest.java b/core/tests/coretests/src/android/os/BuildTest.java
index e8c701e..2a67716a 100644
--- a/core/tests/coretests/src/android/os/BuildTest.java
+++ b/core/tests/coretests/src/android/os/BuildTest.java
@@ -16,8 +16,10 @@
 
 package android.os;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
 import android.platform.test.flag.junit.SetFlagsRule;
@@ -103,4 +105,99 @@
         mSetFlagsRule.disableFlags(Flags.FLAG_ANDROID_OS_BUILD_VANILLA_ICE_CREAM);
         assertFalse(Flags.androidOsBuildVanillaIceCream());
     }
+
+    @Test
+    public void testParseFullVersionCorrectInputMajorDotMinor() throws Exception {
+        int version = Build.parseFullVersion("12.34");
+        assertEquals(12, Build.getMajorSdkVersion(version));
+        assertEquals(34, Build.getMinorSdkVersion(version));
+    }
+
+    @Test
+    public void testParseFullVersionCorrectInputOmitDotMinor() throws Exception {
+        int version = Build.parseFullVersion("1234");
+        assertEquals(1234, Build.getMajorSdkVersion(version));
+        assertEquals(0, Build.getMinorSdkVersion(version));
+    }
+
+    @Test
+    public void testParseFullVersionCorrectInputCurDevelopment() throws Exception {
+        int version = Build.parseFullVersion(Integer.toString(Build.VERSION_CODES.CUR_DEVELOPMENT));
+        assertEquals(Build.VERSION_CODES.CUR_DEVELOPMENT, Build.getMajorSdkVersion(version));
+        assertEquals(0, Build.getMinorSdkVersion(version));
+    }
+
+    @Test
+    public void testParseFullVersionIncorrectInputEmptyString() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> {
+            Build.parseFullVersion("");
+        });
+    }
+
+    @Test
+    public void testParseFullVersionIncorrectInputNoNumbersInString() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> {
+            Build.parseFullVersion("foobar");
+        });
+    }
+
+    @Test
+    public void testParseFullVersionIncorrectInputUnexpectedPatchVersion() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> {
+            Build.parseFullVersion("1.2.3");
+        });
+    }
+
+    @Test
+    public void testParseFullVersionIncorrectInputLeadingDotMissingMajorVersion() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> {
+            Build.parseFullVersion(".1234");
+        });
+    }
+
+    @Test
+    public void testParseFullVersionIncorrectInputTrailingDotMissingMinorVersion()
+            throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> {
+            Build.parseFullVersion("1234.");
+        });
+    }
+
+    @Test
+    public void testParseFullVersionIncorrectInputNegativeMajorVersion() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> {
+            Build.parseFullVersion("-12.34");
+        });
+    }
+
+    @Test
+    public void testParseFullVersionIncorrectInputNegativeMinorVersion() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> {
+            Build.parseFullVersion("12.-34");
+        });
+    }
+
+    @Test
+    public void testFullVersionToStringCorrectInput() throws Exception {
+        assertEquals("0.0", Build.fullVersionToString(0));
+        assertEquals("1.0", Build.fullVersionToString(1 * 100000 + 0));
+        assertEquals("1.1", Build.fullVersionToString(1 * 100000 + 1));
+        assertEquals("12.34", Build.fullVersionToString(12 * 100000 + 34));
+    }
+
+    @Test
+    public void testFullVersionToStringSameStringAfterRoundTripViaParseFullVersion()
+            throws Exception {
+        String s = "12.34";
+        int major = Build.getMajorSdkVersion(Build.parseFullVersion(s));
+        int minor = Build.getMinorSdkVersion(Build.parseFullVersion(s));
+        assertEquals(s, Build.fullVersionToString(major * 100000 + minor));
+    }
+
+    @Test
+    public void testFullVersionToStringIncorrectInputNegativeVersion() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> {
+            Build.fullVersionToString(-1);
+        });
+    }
 }
diff --git a/core/tests/coretests/src/android/os/MessageQueueTest.java b/core/tests/coretests/src/android/os/MessageQueueTest.java
index 549e666..30f6636 100644
--- a/core/tests/coretests/src/android/os/MessageQueueTest.java
+++ b/core/tests/coretests/src/android/os/MessageQueueTest.java
@@ -26,262 +26,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-@Suppress  // Failing.
 @RunWith(AndroidJUnit4.class)
 public class MessageQueueTest {
-    @Rule
-    public final RavenwoodRule mRavenwood = new RavenwoodRule();
 
-    private static class BaseTestHandler extends TestHandlerThread {
-        Handler mHandler;
-        int mLastMessage;
-        int mCount;
-
-        public BaseTestHandler() {
-        }
-
-        public void go() {
-            mHandler = new Handler() {
-                public void handleMessage(Message msg) {
-                    BaseTestHandler.this.handleMessage(msg);
-                }
-            };
-        }
-
-        public void handleMessage(Message msg) {
-            if (!msg.isInUse()) {
-                failure(new RuntimeException(
-                        "msg.isInuse is false, should always be true, #" + msg.what));
-            }
-            if (mCount <= mLastMessage) {
-                if (msg.what != mCount) {
-                    failure(new RuntimeException(
-                            "Expected message #" + mCount
-                                    + ", received #" + msg.what));
-                } else if (mCount == mLastMessage) {
-                    success();
-                }
-                mCount++;
-            } else {
-                failure(new RuntimeException(
-                        "Message received after done, #" + msg.what));
-            }
-        }
-    }
-
-    @Test
-    @MediumTest
-    public void testMessageOrder() throws Exception {
-        TestHandlerThread tester = new BaseTestHandler() {
-            public void go() {
-                super.go();
-                long now = SystemClock.uptimeMillis() + 200;
-                mLastMessage = 4;
-                mCount = 0;
-                mHandler.sendMessageAtTime(mHandler.obtainMessage(2), now + 1);
-                mHandler.sendMessageAtTime(mHandler.obtainMessage(3), now + 2);
-                mHandler.sendMessageAtTime(mHandler.obtainMessage(4), now + 2);
-                mHandler.sendMessageAtTime(mHandler.obtainMessage(0), now + 0);
-                mHandler.sendMessageAtTime(mHandler.obtainMessage(1), now + 0);
-            }
-        };
-
-        tester.doTest(1000);
-    }
-
-    @Test
-    @MediumTest
-    public void testAtFrontOfQueue() throws Exception {
-        TestHandlerThread tester = new BaseTestHandler() {
-            public void go() {
-                super.go();
-                long now = SystemClock.uptimeMillis() + 200;
-                mLastMessage = 3;
-                mCount = 0;
-                mHandler.sendMessageAtTime(mHandler.obtainMessage(3), now);
-                mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(2));
-                mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(0));
-            }
-
-            public void handleMessage(Message msg) {
-                super.handleMessage(msg);
-                if (msg.what == 0) {
-                    mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(1));
-                }
-            }
-        };
-
-        tester.doTest(1000);
-    }
-
-    private static class TestFieldIntegrityHandler extends TestHandlerThread {
-        Handler mHandler;
-        int mLastMessage;
-        int mCount;
-
-        public TestFieldIntegrityHandler() {
-        }
-
-        public void go() {
-            mHandler = new Handler() {
-                public void handleMessage(Message msg) {
-                    TestFieldIntegrityHandler.this.handleMessage(msg);
-                }
-            };
-        }
-
-        public void handleMessage(Message msg) {
-            if (!msg.isInUse()) {
-                failure(new RuntimeException(
-                        "msg.isInuse is false, should always be true, #" + msg.what));
-            }
-            if (mCount <= mLastMessage) {
-                if (msg.what != mCount) {
-                    failure(new RuntimeException(
-                            "Expected message #" + mCount
-                                    + ", received #" + msg.what));
-                } else if (mCount == mLastMessage) {
-                    success();
-                }
-                mCount++;
-            } else {
-                failure(new RuntimeException(
-                        "Message received after done, #" + msg.what));
-            }
-        }
-    }
-
-    @Test
-    @MediumTest
-    public void testFieldIntegrity() throws Exception {
-
-        TestHandlerThread tester = new TestFieldIntegrityHandler() {
-            Bundle mBundle;
-
-            public void go() {
-                super.go();
-                mLastMessage = 1;
-                mCount = 0;
-                mHandler.sendMessage(mHandler.obtainMessage(0));
-            }
-
-            public void handleMessage(Message msg) {
-                super.handleMessage(msg);
-                if (msg.what == 0) {
-                    msg.flags = Message.FLAGS_TO_CLEAR_ON_COPY_FROM;
-                    msg.what = 1;
-                    msg.arg1 = 456;
-                    msg.arg2 = 789;
-                    msg.obj = this;
-                    msg.replyTo = null;
-                    mBundle = new Bundle();
-                    msg.data = mBundle;
-                    msg.data.putString("key", "value");
-
-                    Message newMsg = mHandler.obtainMessage();
-                    newMsg.copyFrom(msg);
-                    if (newMsg.isInUse() != false) {
-                        failure(new RuntimeException(
-                                "newMsg.isInUse is true should be false after copyFrom"));
-                    }
-                    if (newMsg.flags != 0) {
-                        failure(new RuntimeException(String.format(
-                        "newMsg.flags is %d should be 0 after copyFrom", newMsg.flags)));
-                    }
-                    if (newMsg.what != 1) {
-                        failure(new RuntimeException(String.format(
-                                "newMsg.what is %d should be %d after copyFrom", newMsg.what, 1)));
-                    }
-                    if (newMsg.arg1 != 456) {
-                        failure(new RuntimeException(String.format(
-                                "newMsg.arg1 is %d should be %d after copyFrom", msg.arg1, 456)));
-                    }
-                    if (newMsg.arg2 != 789) {
-                        failure(new RuntimeException(String.format(
-                                "newMsg.arg2 is %d should be %d after copyFrom", msg.arg2, 789)));
-                    }
-                    if (newMsg.obj != this) {
-                        failure(new RuntimeException(
-                                "newMsg.obj should be 'this' after copyFrom"));
-                    }
-                    if (newMsg.replyTo != null) {
-                        failure(new RuntimeException(
-                                "newMsg.replyTo should be null after copyFrom"));
-                    }
-                    if (newMsg.data == mBundle) {
-                        failure(new RuntimeException(
-                                "newMsg.data should NOT be mBundle after copyFrom"));
-                    }
-                    if (!newMsg.data.getString("key").equals(mBundle.getString("key"))) {
-                        failure(new RuntimeException(String.format(
-                                "newMsg.data.getString(\"key\") is %s and does not equal" +
-                                " mBundle.getString(\"key\") which is %s after copyFrom",
-                                newMsg.data.getString("key"),  mBundle.getString("key"))));
-                    }
-                    if (newMsg.when != 0) {
-                        failure(new RuntimeException(String.format(
-                                "newMsg.when is %d should be 0 after copyFrom", newMsg.when)));
-                    }
-                    if (newMsg.target != mHandler) {
-                        failure(new RuntimeException(
-                                "newMsg.target is NOT mHandler after copyFrom"));
-                    }
-                    if (newMsg.callback != null) {
-                        failure(new RuntimeException(
-                                "newMsg.callback is NOT null after copyFrom"));
-                    }
-
-                    mHandler.sendMessage(newMsg);
-                } else if (msg.what == 1) {
-                    if (msg.isInUse() != true) {
-                        failure(new RuntimeException(String.format(
-                                "msg.isInUse is false should be true after when processing %d",
-                                msg.what)));
-                    }
-                    if (msg.arg1 != 456) {
-                        failure(new RuntimeException(String.format(
-                                "msg.arg1 is %d should be %d when processing # %d",
-                                msg.arg1, 456, msg.what)));
-                    }
-                    if (msg.arg2 != 789) {
-                        failure(new RuntimeException(String.format(
-                                "msg.arg2 is %d should be %d when processing # %d",
-                                msg.arg2, 789, msg.what)));
-                    }
-                    if (msg.obj != this) {
-                        failure(new RuntimeException(String.format(
-                                "msg.obj should be 'this' when processing # %d", msg.what)));
-                    }
-                    if (msg.replyTo != null) {
-                        failure(new RuntimeException(String.format(
-                                "msg.replyTo should be null when processing # %d", msg.what)));
-                    }
-                    if (!msg.data.getString("key").equals(mBundle.getString("key"))) {
-                        failure(new RuntimeException(String.format(
-                                "msg.data.getString(\"key\") is %s and does not equal" +
-                                " mBundle.getString(\"key\") which is %s when processing # %d",
-                                msg.data.getString("key"),  mBundle.getString("key"), msg.what)));
-                    }
-                    if (msg.when != 0) {
-                        failure(new RuntimeException(String.format(
-                                "msg.when is %d should be 0 when processing # %d",
-                                msg.when, msg.what)));
-                    }
-                    if (msg.target != null) {
-                        failure(new RuntimeException(String.format(
-                                "msg.target is NOT null when processing # %d", msg.what)));
-                    }
-                    if (msg.callback != null) {
-                        failure(new RuntimeException(String.format(
-                                "msg.callback is NOT null when processing # %d", msg.what)));
-                    }
-                } else {
-                    failure(new RuntimeException(String.format(
-                            "Unexpected msg.what is %d" + msg.what)));
-                }
-            }
-        };
-
-        tester.doTest(1000);
-    }
 }
diff --git a/core/tests/coretests/src/android/os/OWNERS b/core/tests/coretests/src/android/os/OWNERS
index 4620cb8..c45080f 100644
--- a/core/tests/coretests/src/android/os/OWNERS
+++ b/core/tests/coretests/src/android/os/OWNERS
@@ -15,3 +15,6 @@
 
 # RemoteCallbackList
 per-file RemoteCallbackListTest.java = shayba@google.com
+
+# MessageQueue
+per-file MessageQueueTest.java = mfasheh@google.com, shayba@google.com
diff --git a/core/tests/coretests/src/android/os/PowerManagerTest.java b/core/tests/coretests/src/android/os/PowerManagerTest.java
index e4e965f..b8d1979 100644
--- a/core/tests/coretests/src/android/os/PowerManagerTest.java
+++ b/core/tests/coretests/src/android/os/PowerManagerTest.java
@@ -30,11 +30,10 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
-import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.annotations.DisabledOnRavenwood;
 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.RavenwoodFlagsValueProvider;
 import android.platform.test.ravenwood.RavenwoodRule;
 
 import androidx.test.InstrumentationRegistry;
@@ -54,7 +53,7 @@
 import java.util.concurrent.Executors;
 
 @RunWith(AndroidJUnit4.class)
-@IgnoreUnderRavenwood(blockedBy = PowerManager.class)
+@DisabledOnRavenwood(blockedBy = PowerManager.class)
 public class PowerManagerTest {
 
     private static final String TAG = "PowerManagerTest";
@@ -83,19 +82,14 @@
             String[] keys, String[] values);
 
     static {
-        if (!RavenwoodRule.isUnderRavenwood()) {
+        if (!RavenwoodRule.isOnRavenwood()) {
             System.loadLibrary("powermanagertest_jni");
         }
     }
 
-    @Rule
-    public final RavenwoodRule mRavenwood = new RavenwoodRule();
-
     // Required for RequiresFlagsEnabled and RequiresFlagsDisabled annotations to take effect.
     @Rule
-    public final CheckFlagsRule mCheckFlagsRule = RavenwoodRule.isOnRavenwood()
-            ? RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule()
-            : DeviceFlagsValueProvider.createCheckFlagsRule();
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
 
     /**
      * Setup any common data for the upcoming tests.
diff --git a/core/tests/coretests/src/android/os/WorkDurationUnitTest.java b/core/tests/coretests/src/android/os/WorkDurationUnitTest.java
index 58a434a..a04a662 100644
--- a/core/tests/coretests/src/android/os/WorkDurationUnitTest.java
+++ b/core/tests/coretests/src/android/os/WorkDurationUnitTest.java
@@ -18,12 +18,10 @@
 
 import static org.junit.Assert.assertThrows;
 
-import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.annotations.DisabledOnRavenwood;
 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.RavenwoodFlagsValueProvider;
-import android.platform.test.ravenwood.RavenwoodRule;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
@@ -34,16 +32,11 @@
 import org.mockito.MockitoAnnotations;
 
 @RunWith(AndroidJUnit4.class)
-@IgnoreUnderRavenwood(blockedBy = WorkDuration.class)
+@DisabledOnRavenwood(blockedBy = WorkDuration.class)
 public class WorkDurationUnitTest {
-    @Rule
-    public final RavenwoodRule mRavenwood = new RavenwoodRule();
-
     // Required for RequiresFlagsEnabled and RequiresFlagsDisabled annotations to take effect.
     @Rule
-    public final CheckFlagsRule mCheckFlagsRule = RavenwoodRule.isOnRavenwood()
-            ? RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule()
-            : DeviceFlagsValueProvider.createCheckFlagsRule();
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
 
     @Before
     public void setUp() {
diff --git a/core/tests/coretests/src/android/view/ScrollCaptureSearchResultsTest.java b/core/tests/coretests/src/android/view/ScrollCaptureSearchResultsTest.java
index 726ee85..915ace0 100644
--- a/core/tests/coretests/src/android/view/ScrollCaptureSearchResultsTest.java
+++ b/core/tests/coretests/src/android/view/ScrollCaptureSearchResultsTest.java
@@ -16,9 +16,9 @@
 
 package android.view;
 
-import static androidx.test.InstrumentationRegistry.getTargetContext;
+import static android.view.flags.Flags.FLAG_SCROLL_CAPTURE_TARGET_Z_ORDER_FIX;
 
-import static com.google.common.truth.Truth.assertThat;
+import static androidx.test.InstrumentationRegistry.getTargetContext;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
@@ -32,13 +32,16 @@
 import android.graphics.Rect;
 import android.os.CancellationSignal;
 import android.os.SystemClock;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
 
 import androidx.annotation.NonNull;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -56,6 +59,8 @@
 @RunWith(AndroidJUnit4.class)
 public class ScrollCaptureSearchResultsTest {
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
     private static final Rect EMPTY_RECT = new Rect();
     private static final String TAG = "Test";
@@ -98,6 +103,45 @@
         assertNull("Expected null due to no valid targets", results.getTopResult());
     }
 
+    /**
+     * A scrolling target should be excluded even when larger if it will be drawn over by another
+     * scrolling target.
+     */
+    @EnableFlags(FLAG_SCROLL_CAPTURE_TARGET_Z_ORDER_FIX)
+    @Test
+    public void testCoveredTargetsAreExcluded() {
+        ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(mDirectExec);
+
+        FakeScrollCaptureCallback callback1 = new FakeScrollCaptureCallback(mDirectExec);
+        callback1.setScrollBounds(new Rect(0, 0, 200, 200)); // 200 tall
+        View view1 = new FakeView(getTargetContext(), 0, 0, 200, 200, 1);
+        ScrollCaptureTarget target1 = createTargetWithView(view1, callback1,
+                new Rect(0, 0, 200, 200), new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
+
+        FakeScrollCaptureCallback callback2 = new FakeScrollCaptureCallback(mDirectExec);
+        callback2.setScrollBounds(new Rect(0, 0, 200, 180)); // 180 tall
+        View view2 = new FakeView(getTargetContext(), 0, 20, 200, 200, 2);
+        ScrollCaptureTarget target2 = createTargetWithView(view2, callback2,
+                new Rect(0, 0, 200, 180), new Point(0, 20), View.SCROLL_CAPTURE_HINT_AUTO);
+
+        // Top z-order but smaller, and non-intersecting. (positioned further Y than the first two)
+        FakeScrollCaptureCallback callback3 = new FakeScrollCaptureCallback(mDirectExec);
+        callback3.setScrollBounds(new Rect(0, 0, 50, 50));
+        View view3 = new FakeView(getTargetContext(), 75, 250, 125, 300, 3);
+        ScrollCaptureTarget target3 = createTargetWithView(view3, callback3,
+                new Rect(0, 0, 50, 50), new Point(75, 250), View.SCROLL_CAPTURE_HINT_AUTO);
+
+        results.addTarget(target1);
+        results.addTarget(target2);
+        results.addTarget(target3);
+
+        assertTrue(results.isComplete());
+        ScrollCaptureTarget result = results.getTopResult();
+        assertSame("Expected the second target because of higher z-Index", target2, result);
+        assertEquals("result has wrong scroll bounds",
+                new Rect(0, 0, 200, 180), result.getScrollBounds());
+    }
+
     @Test
     public void testSingleTarget() {
         ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(mDirectExec);
@@ -152,29 +196,29 @@
 
         // 2 - 10x10 + HINT_INCLUDE
         FakeScrollCaptureCallback callback2 = new FakeScrollCaptureCallback(mDirectExec);
-        callback2.setScrollBounds(new Rect(0, 0, 10, 10));
-        ViewGroup targetView2 = new FakeView(getTargetContext(), 0, 0, 60, 60, 2);
+        callback2.setScrollBounds(new Rect(25, 25, 35, 35)); // 10x10
+        ViewGroup targetView2 = new FakeView(getTargetContext(), 0, 60, 60, 120, 2);
         ScrollCaptureTarget target2 = createTargetWithView(targetView2, callback2,
                  new Rect(0, 0, 60, 60), new Point(0, 0), View.SCROLL_CAPTURE_HINT_INCLUDE);
 
         // 3 - 20x20 + AUTO
         FakeScrollCaptureCallback callback3 = new FakeScrollCaptureCallback(mDirectExec);
         callback3.setScrollBounds(new Rect(0, 0, 20, 20));
-        ViewGroup targetView3 = new FakeView(getTargetContext(), 0, 0, 60, 60, 3);
+        ViewGroup targetView3 = new FakeView(getTargetContext(), 0, 120, 60, 180, 3);
         ScrollCaptureTarget target3 = createTargetWithView(targetView3, callback3,
                 new Rect(0, 0, 60, 60), new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
 
         // 4 - 30x30 + AUTO
         FakeScrollCaptureCallback callback4 = new FakeScrollCaptureCallback(mDirectExec);
         callback4.setScrollBounds(new Rect(0, 0, 10, 10));
-        ViewGroup targetView4 = new FakeView(getTargetContext(), 0, 0, 60, 60, 4);
+        ViewGroup targetView4 = new FakeView(getTargetContext(), 0, 180, 60, 240, 4);
         ScrollCaptureTarget target4 = createTargetWithView(targetView4, callback4,
                 new Rect(0, 0, 60, 60), new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
 
         // 5 - 10x10 + child of #4
         FakeScrollCaptureCallback callback5 = new FakeScrollCaptureCallback(mDirectExec);
         callback5.setScrollBounds(new Rect(0, 0, 10, 10));
-        ViewGroup targetView5 = new FakeView(getTargetContext(), 0, 0, 60, 60, 5);
+        ViewGroup targetView5 = new FakeView(getTargetContext(), 0, 0, 60, 30, 5);
         ScrollCaptureTarget target5 = createTargetWithView(targetView5, callback5,
                 new Rect(0, 0, 60, 60), new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
         targetView4.addView(targetView5);
@@ -182,7 +226,7 @@
         // 6 - 20x20 + child of #4
         FakeScrollCaptureCallback callback6 = new FakeScrollCaptureCallback(mDirectExec);
         callback6.setScrollBounds(new Rect(0, 0, 20, 20));
-        ViewGroup targetView6 = new FakeView(getTargetContext(), 0, 0, 60, 60, 6);
+        ViewGroup targetView6 = new FakeView(getTargetContext(), 0, 30, 30, 60, 6);
         ScrollCaptureTarget target6 = createTargetWithView(targetView6, callback6,
                 new Rect(0, 0, 60, 60), new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
         targetView4.addView(targetView6);
@@ -194,20 +238,10 @@
         results.addTarget(target4);
         results.addTarget(target5);
         results.addTarget(target6);
-        assertTrue(results.isComplete());
+        assertTrue("results.isComplete()", results.isComplete());
 
         // Verify "top" result
-        assertEquals(target2, results.getTopResult());
-
-        // Verify priority ("best" first)
-        assertThat(results.getTargets())
-                .containsExactly(
-                        target2,
-                        target6,
-                        target5,
-                        target4,
-                        target3,
-                        target1);
+        assertEquals("top result", target2, results.getTopResult());
     }
 
     /**
@@ -291,27 +325,22 @@
                 new Rect(1, 2, 3, 4), result.getScrollBounds());
     }
 
-    private void setupTargetView(View view, Rect localVisibleRect, int scrollCaptureHint) {
-        view.setScrollCaptureHint(scrollCaptureHint);
-        view.onVisibilityAggregated(true);
-        // Treat any offset as padding, outset localVisibleRect on all sides and use this as
-        // child bounds
-        Rect bounds = new Rect(localVisibleRect);
-        bounds.inset(-bounds.left, -bounds.top, bounds.left, bounds.top);
-        view.layout(bounds.left, bounds.top, bounds.right, bounds.bottom);
-        view.onVisibilityAggregated(true);
-    }
-
     private ScrollCaptureTarget createTarget(ScrollCaptureCallback callback, Rect localVisibleRect,
             Point positionInWindow, int scrollCaptureHint) {
-        View mockView = new View(getTargetContext());
+        Rect bounds = new Rect(localVisibleRect);
+        // Use localVisibleRect as position, treat left/top offset as padding
+        bounds.left = 0;
+        bounds.top = 0;
+        View mockView = new FakeView(getTargetContext(), bounds.left, bounds.top, bounds.right,
+                bounds.bottom, View.NO_ID);
         return createTargetWithView(mockView, callback, localVisibleRect, positionInWindow,
                 scrollCaptureHint);
     }
 
     private ScrollCaptureTarget createTargetWithView(View view, ScrollCaptureCallback callback,
             Rect localVisibleRect, Point positionInWindow, int scrollCaptureHint) {
-        setupTargetView(view, localVisibleRect, scrollCaptureHint);
+        view.setScrollCaptureHint(scrollCaptureHint);
+        view.onVisibilityAggregated(true);
         return new ScrollCaptureTarget(view, localVisibleRect, positionInWindow, callback);
     }
 
@@ -326,6 +355,32 @@
         @Override
         protected void onLayout(boolean changed, int l, int t, int r, int b) {
         }
+
+        /** Ignores window attachment state. The standard impl always returns [0,0] if the view is
+         *  not attached. This override allows testing without dealing with AttachInfo.
+         */
+        @Override
+        public void getLocationInWindow(int[] outLocation) {
+            outLocation[0] = mLeft;
+            outLocation[1] = mTop;
+            ViewParent viewParent = getParent();
+            while (viewParent instanceof View) {
+                final View view = (View) viewParent;
+
+                outLocation[0] -= view.mScrollX;
+                outLocation[1] -= view.mScrollY;
+
+                // Explicitly do not handle matrix/transforms, not needed for testing
+                if (!view.hasIdentityMatrix()) {
+                    throw new IllegalStateException("This mock does not handle transforms!");
+                }
+
+                outLocation[0] += view.mLeft;
+                outLocation[1] += view.mTop;
+
+                viewParent = view.mParent;
+            }
+        }
     }
 
     static class FakeScrollCaptureCallback implements ScrollCaptureCallback {
diff --git a/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java b/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java
index 25608c3..adf7a72 100644
--- a/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java
+++ b/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import static android.view.flags.Flags.FLAG_SCROLL_CAPTURE_TARGET_Z_ORDER_FIX;
+
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import static org.junit.Assert.assertEquals;
@@ -30,16 +32,20 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.CancellationSignal;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
 
 import androidx.annotation.NonNull;
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.junit.MockitoJUnitRunner;
 
+import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
@@ -51,6 +57,9 @@
 @RunWith(MockitoJUnitRunner.class)
 public class ViewGroupScrollCaptureTest {
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     private static final Executor DIRECT_EXECUTOR = Runnable::run;
 
     /** Make sure the hint flags are saved and loaded correctly. */
@@ -239,6 +248,56 @@
         assertNull(results.getTopResult());
     }
 
+    @EnableFlags(FLAG_SCROLL_CAPTURE_TARGET_Z_ORDER_FIX)
+    @MediumTest
+    @Test
+    public void testDispatchScrollCaptureSearch_traversesInDrawingOrder() throws Exception {
+        final Context context = getInstrumentation().getContext();
+        // Uses childDrawingOrder to reverse drawing order of children.
+        final MockViewGroup viewGroup = new MockViewGroup(context, 0, 0, 200, 200);
+
+        // w=200, h=180, z=10, drawn on top
+        final MockView view1 = new MockView(context, 0, 20, 200, 200);
+        TestScrollCaptureCallback callback1 = new TestScrollCaptureCallback();
+        view1.setScrollCaptureCallback(callback1);
+        view1.setZ(10f);
+
+        // w=200, h=200, z=0, drawn first, under view1
+        final MockView view2 = new MockView(context, 0, 0, 200, 200);
+        TestScrollCaptureCallback callback2 = new TestScrollCaptureCallback();
+        view2.setScrollCaptureCallback(callback2);
+
+        viewGroup.addView(view1); // test order is dependent on draw order by adding z=10 first
+        viewGroup.addView(view2);
+
+        Rect localVisibleRect = new Rect(0, 0, 200, 200);
+        Point windowOffset = new Point(0, 0);
+
+        // Where targets are added
+        final ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(DIRECT_EXECUTOR);
+
+        viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, results::addTarget);
+        callback1.completeSearchRequest(new Rect(0, 0, 200, 180));
+        callback2.completeSearchRequest(new Rect(0, 0, 200, 200));
+        assertTrue(results.isComplete());
+
+        List<ScrollCaptureTarget> targets = results.getTargets();
+        List<View> targetViews =
+                targets.stream().map(ScrollCaptureTarget::getContainingView).toList();
+        assertEquals(List.of(view2,  view1), targetViews);
+    }
+
+    static final class ReverseDrawingViewGroup extends MockViewGroup {
+        ReverseDrawingViewGroup(Context context, int left, int top, int right, int bottom) {
+            super(context, left, top, right, bottom, View.SCROLL_CAPTURE_HINT_AUTO);
+        }
+
+        @Override
+        protected int getChildDrawingOrder(int childCount, int drawingPosition) {
+            return childCount == 0 ? 0 : childCount - (drawingPosition + 1);
+        }
+    }
+
     /**
      * Test scroll capture search dispatch to child views.
      * <p>
@@ -511,7 +570,7 @@
         }
     };
 
-    public static final class MockViewGroup extends ViewGroup {
+    public static class MockViewGroup extends ViewGroup {
         private ScrollCaptureCallback mInternalCallback;
         private Rect mOnScrollCaptureSearchLastLocalVisibleRect;
         private Point mOnScrollCaptureSearchLastWindowOffset;
diff --git a/core/tests/coretests/src/android/widget/ProgressBarTest.java b/core/tests/coretests/src/android/widget/ProgressBarTest.java
index fa6dd31..0cbfaa9 100644
--- a/core/tests/coretests/src/android/widget/ProgressBarTest.java
+++ b/core/tests/coretests/src/android/widget/ProgressBarTest.java
@@ -23,8 +23,12 @@
 
 import android.app.Instrumentation;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.view.View;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.Flags;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
@@ -32,6 +36,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -40,6 +45,10 @@
 @Presubmit
 public class ProgressBarTest {
     private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
+
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
     private ProgressBar mBar;
     private AccessibilityNodeInfo mInfo;
 
@@ -181,4 +190,16 @@
         mBar.onInitializeAccessibilityNodeInfo(mInfo);
         assertEquals("custom state", mInfo.getStateDescription().toString());
     }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_INDETERMINATE_RANGE_INFO)
+    public void testRangeInfo_indeterminateProgressBar_usesTypeIndeterminate() {
+        mBar.setIndeterminate(true);
+        assertTrue(mBar.isIndeterminate());
+
+        mBar.onInitializeAccessibilityNodeInfo(mInfo);
+
+        assertEquals(mInfo.getRangeInfo().getType(),
+                AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INDETERMINATE);
+    }
 }
diff --git a/core/tests/coretests/src/android/window/OWNERS b/core/tests/coretests/src/android/window/OWNERS
index 6c80cf9..b3fcea2 100644
--- a/core/tests/coretests/src/android/window/OWNERS
+++ b/core/tests/coretests/src/android/window/OWNERS
@@ -1,2 +1,3 @@
 include /services/core/java/com/android/server/wm/OWNERS
-charlesccchen@google.com
+
+# Bug component: 1519745 = per-file WindowContext*,WindowMetrics*,WindowProvider*,WindowTokenClient*
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/window/WindowContextTest.java b/core/tests/coretests/src/android/window/WindowContextTest.java
index f1fbd55..21930d1 100644
--- a/core/tests/coretests/src/android/window/WindowContextTest.java
+++ b/core/tests/coretests/src/android/window/WindowContextTest.java
@@ -29,6 +29,11 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
 import android.app.Activity;
 import android.app.EmptyActivity;
@@ -60,6 +65,8 @@
 
 import com.android.frameworks.coretests.R;
 
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -88,9 +95,21 @@
     private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
     private final WindowContext mWindowContext = createWindowContext();
     private final IWindowManager mWms = WindowManagerGlobal.getWindowManagerService();
+    private WindowTokenClientController mOriginalWindowTokenClientController;
 
     private static final int TIMEOUT_IN_SECONDS = 4;
 
+    @Before
+    public void setUp() {
+        // Keeping the original to set it back after each test, in case they applied any override.
+        mOriginalWindowTokenClientController = WindowTokenClientController.getInstance();
+    }
+
+    @After
+    public void tearDown() {
+        WindowTokenClientController.overrideForTesting(mOriginalWindowTokenClientController);
+    }
+
     @Test
     public void testCreateWindowContextWindowManagerAttachClientToken() {
         final WindowManager windowContextWm = WindowManagerImpl
@@ -320,6 +339,20 @@
         }
     }
 
+    @Test
+    public void updateDisplay_wasAttached_detachThenAttachedPropagatedToTokenController() {
+        final WindowTokenClientController mockWindowTokenClientController =
+                mock(WindowTokenClientController.class);
+        WindowTokenClientController.overrideForTesting(mockWindowTokenClientController);
+
+        mWindowContext.updateDisplay(DEFAULT_DISPLAY + 1);
+
+        verify(mockWindowTokenClientController).detachIfNeeded(any());
+        verify(mockWindowTokenClientController).attachToDisplayArea(any(),
+                anyInt(), /* displayId= */ eq(DEFAULT_DISPLAY + 1),
+                any());
+    }
+
     private WindowContext createWindowContext() {
         return createWindowContext(TYPE_APPLICATION_OVERLAY);
     }
diff --git a/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java b/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java
index a3725af..bb2fe1b 100644
--- a/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java
+++ b/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java
@@ -162,6 +162,22 @@
     }
 
     @Test
+    public void testAttachToDisplayContent_keepTrackWithoutWMS() {
+        // WMS is not initialized
+        doReturn(null).when(mController).getWindowManagerService();
+
+        assertFalse(mController.attachToDisplayContent(mWindowTokenClient, DEFAULT_DISPLAY));
+
+        // Can report config change
+        mController.onWindowContextInfoChanged(mWindowTokenClient, mWindowContextInfo);
+
+        verify(mWindowTokenClient).onConfigurationChanged(mConfiguration, DEFAULT_DISPLAY);
+
+        // No crash to detach even if WMS is not initialized.
+        mController.detachIfNeeded(mWindowTokenClient);
+    }
+
+    @Test
     public void testAttachToWindowToken() throws RemoteException {
         doReturn(null).when(mWindowManagerService).attachWindowContextToWindowToken(
                 any(), any(), any());
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 f78bc92..a6466c5 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -16,7 +16,6 @@
 
 package com.android.internal.accessibility;
 
-import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS;
 import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN;
 import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN;
 import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
@@ -64,7 +63,6 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.Vibrator;
-import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
@@ -423,7 +421,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void testClickingDisableButtonInDialog_shouldClearShortcutId() throws Exception {
         configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
         configureValidShortcutService();
@@ -446,58 +443,6 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
-    public void testClickingDisableButtonInDialog_shouldClearShortcutId_old() throws Exception {
-        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
-        configureValidShortcutService();
-        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
-                AccessibilityShortcutController.DialogStatus.NOT_SHOWN);
-        getController().performAccessibilityShortcut();
-
-        ArgumentCaptor<DialogInterface.OnClickListener> captor =
-                ArgumentCaptor.forClass(DialogInterface.OnClickListener.class);
-        verify(mAlertDialogBuilder).setPositiveButton(eq(R.string.accessibility_shortcut_off),
-                captor.capture());
-        captor.getValue().onClick(null, DialogInterface.BUTTON_POSITIVE);
-
-        assertThat(
-                Settings.Secure.getString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE)
-        ).isEmpty();
-        assertThat(Settings.Secure.getInt(
-                mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN)).isEqualTo(
-                AccessibilityShortcutController.DialogStatus.NOT_SHOWN);
-    }
-
-    @Test
-    @EnableFlags(Flags.FLAG_UPDATE_ALWAYS_ON_A11Y_SERVICE)
-    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
-    public void turnOffVolumeShortcutForAlwaysOnA11yService_shouldTurnOffA11yService()
-            throws Exception {
-        configureApplicationTargetSdkVersion(Build.VERSION_CODES.R);
-        turnOffVolumeKeyShortcutForA11yService(/* alwaysOnService= */ true);
-
-        assertThat(
-                Settings.Secure.getString(mContentResolver, ENABLED_ACCESSIBILITY_SERVICES)
-        ).isEmpty();
-    }
-
-    @Test
-    @EnableFlags(Flags.FLAG_UPDATE_ALWAYS_ON_A11Y_SERVICE)
-    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
-    public void turnOffVolumeShortcutForAlwaysOnA11yService_hasOtherTypesShortcut_shouldNotTurnOffA11yService()
-            throws Exception {
-        configureApplicationTargetSdkVersion(Build.VERSION_CODES.R);
-        Settings.Secure.putString(
-                mContentResolver, ACCESSIBILITY_BUTTON_TARGETS, SERVICE_NAME_STRING);
-
-        turnOffVolumeKeyShortcutForA11yService(/* alwaysOnService= */ true);
-
-        assertThat(
-                Settings.Secure.getString(mContentResolver, ENABLED_ACCESSIBILITY_SERVICES)
-        ).isEqualTo(SERVICE_NAME_STRING);
-    }
-
-    @Test
     public void turnOffVolumeShortcutForStandardA11yService_shouldNotTurnOffA11yService()
             throws Exception {
         turnOffVolumeKeyShortcutForA11yService(/* alwaysOnService= */ false);
@@ -530,7 +475,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void testTurnOnDefaultA11yServiceInDialog_defaultServiceShortcutTurnsOn()
             throws Exception {
         configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
@@ -554,30 +498,6 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
-    public void testTurnOnDefaultA11yServiceInDialog_defaultServiceShortcutTurnsOn_old()
-            throws Exception {
-        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
-        configureDefaultAccessibilityService();
-        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
-                AccessibilityShortcutController.DialogStatus.NOT_SHOWN);
-        getController().performAccessibilityShortcut();
-
-        ArgumentCaptor<DialogInterface.OnClickListener> captor =
-                ArgumentCaptor.forClass(DialogInterface.OnClickListener.class);
-        verify(mAlertDialogBuilder).setNegativeButton(eq(R.string.accessibility_shortcut_on),
-                captor.capture());
-        captor.getValue().onClick(null, DialogInterface.BUTTON_NEGATIVE);
-
-        assertThat(Settings.Secure.getString(mContentResolver,
-                ACCESSIBILITY_SHORTCUT_TARGET_SERVICE)).isEqualTo(SERVICE_NAME_STRING);
-        assertThat(Settings.Secure.getInt(
-                mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN)).isEqualTo(
-                AccessibilityShortcutController.DialogStatus.SHOWN);
-    }
-
-    @Test
-    @EnableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void testTurnOffDefaultA11yServiceInDialog_defaultServiceShortcutTurnsOff()
             throws Exception {
         configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
@@ -601,29 +521,6 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
-    public void testTurnOffDefaultA11yServiceInDialog_defaultServiceShortcutTurnsOff_old()
-            throws Exception {
-        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
-        configureDefaultAccessibilityService();
-        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
-                AccessibilityShortcutController.DialogStatus.NOT_SHOWN);
-        getController().performAccessibilityShortcut();
-
-        ArgumentCaptor<DialogInterface.OnClickListener> captor =
-                ArgumentCaptor.forClass(DialogInterface.OnClickListener.class);
-        verify(mAlertDialogBuilder).setPositiveButton(eq(R.string.accessibility_shortcut_off),
-                captor.capture());
-        captor.getValue().onClick(null, DialogInterface.BUTTON_POSITIVE);
-
-        assertThat(Settings.Secure.getString(mContentResolver,
-                ACCESSIBILITY_SHORTCUT_TARGET_SERVICE)).isEmpty();
-        assertThat(Settings.Secure.getInt(
-                mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN)).isEqualTo(
-                AccessibilityShortcutController.DialogStatus.NOT_SHOWN);
-    }
-
-    @Test
     public void testOnAccessibilityShortcut_afterDialogShown_shouldCallServer() throws Exception {
         configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
         configureValidShortcutService();
@@ -638,9 +535,7 @@
     }
 
     @Test
-    @EnableFlags({
-            Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS,
-            Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE})
+    @EnableFlags(Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE)
     public void testOnAccessibilityShortcut_settingNull_dialogShown_enablesDefaultShortcut()
             throws Exception {
         configureDefaultAccessibilityService();
@@ -658,24 +553,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE)
-    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
-    public void testOnAccessibilityShortcut_settingNull_dialogShown_writesDefaultSetting()
-            throws Exception {
-        configureDefaultAccessibilityService();
-        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
-                AccessibilityShortcutController.DialogStatus.SHOWN);
-        // Setting is only `null` during SUW.
-        Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null);
-        getController().performAccessibilityShortcut();
-
-        assertThat(Settings.Secure.getString(mContentResolver,
-                ACCESSIBILITY_SHORTCUT_TARGET_SERVICE)).isEqualTo(SERVICE_NAME_STRING);
-        verify(mAccessibilityManagerService).performAccessibilityShortcut(
-                Display.DEFAULT_DISPLAY, HARDWARE, null);
-    }
-
-    @Test
     public void getFrameworkFeatureMap_shouldBeUnmodifiable() {
         final Map<ComponentName, AccessibilityShortcutController.FrameworkFeatureInfo>
                 frameworkFeatureMap =
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 5339d91..acf7dbc 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
@@ -33,12 +33,7 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.platform.test.annotations.DisableFlags;
-import android.platform.test.annotations.EnableFlags;
-import android.platform.test.flag.junit.SetFlagsRule;
-import android.provider.Settings;
 import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.Flags;
 import android.view.accessibility.IAccessibilityManager;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -68,8 +63,6 @@
 @RunWith(AndroidJUnit4.class)
 public class InvisibleToggleAccessibilityServiceTargetTest {
     @Rule
-    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
-    @Rule
     public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
     @Mock
     private IAccessibilityManager mAccessibilityManagerService;
@@ -117,7 +110,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void onCheckedChanged_true_callA11yManagerToUpdateShortcuts() throws Exception {
         mSut.onCheckedChanged(true);
 
@@ -130,7 +122,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void onCheckedChanged_false_callA11yManagerToUpdateShortcuts() throws Exception {
         mSut.onCheckedChanged(false);
         verify(mAccessibilityManagerService).enableShortcutsForTargets(
@@ -140,86 +131,4 @@
                 anyInt());
         assertThat(mListCaptor.getValue()).containsExactly(ALWAYS_ON_SERVICE_COMPONENT_NAME);
     }
-
-    @Test
-    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
-    public void onCheckedChanged_turnOnShortcut_hasOtherShortcut_serviceKeepsOn() {
-        enableA11yService(/* enable= */ true);
-        addShortcutForA11yService(
-                Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, /* add= */ false);
-        addShortcutForA11yService(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, /* add= */ true);
-
-        mSut.onCheckedChanged(/* isChecked= */ true);
-
-        assertA11yServiceState(/* enabled= */ true);
-    }
-
-    @Test
-    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
-    public void onCheckedChanged_turnOnShortcut_noOtherShortcut_shouldTurnOnService() {
-        enableA11yService(/* enable= */ false);
-        addShortcutForA11yService(
-                Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, /* add= */ false);
-        addShortcutForA11yService(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, /* add= */ false);
-
-        mSut.onCheckedChanged(/* isChecked= */ true);
-
-        assertA11yServiceState(/* enabled= */ true);
-    }
-
-    @Test
-    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
-    public void onCheckedChanged_turnOffShortcut_hasOtherShortcut_serviceKeepsOn() {
-        enableA11yService(/* enable= */ true);
-        addShortcutForA11yService(
-                Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, /* add= */ true);
-        addShortcutForA11yService(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, /* add= */ true);
-
-        mSut.onCheckedChanged(/* isChecked= */ false);
-
-        assertA11yServiceState(/* enabled= */ true);
-    }
-
-    @Test
-    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
-    public void onCheckedChanged_turnOffShortcut_noOtherShortcut_shouldTurnOffService() {
-        enableA11yService(/* enable= */ true);
-        addShortcutForA11yService(
-                Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, /* add= */ true);
-        addShortcutForA11yService(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, /* add= */ false);
-
-        mSut.onCheckedChanged(/* isChecked= */ false);
-
-        assertA11yServiceState(/* enabled= */ false);
-    }
-
-    private void enableA11yService(boolean enable) {
-        Settings.Secure.putString(
-                mContextSpy.getContentResolver(),
-                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
-                enable ? ALWAYS_ON_SERVICE_COMPONENT_NAME : "");
-    }
-
-    private void addShortcutForA11yService(String shortcutKey, boolean add) {
-        Settings.Secure.putString(
-                mContextSpy.getContentResolver(),
-                shortcutKey,
-                add ? ALWAYS_ON_SERVICE_COMPONENT_NAME : "");
-    }
-
-    private void assertA11yServiceState(boolean enabled) {
-        if (enabled) {
-            assertThat(
-                    Settings.Secure.getString(
-                            mContextSpy.getContentResolver(),
-                            Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES)
-            ).contains(ALWAYS_ON_SERVICE_COMPONENT_NAME);
-        } else {
-            assertThat(
-                    Settings.Secure.getString(
-                            mContextSpy.getContentResolver(),
-                            Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES)
-            ).doesNotContain(ALWAYS_ON_SERVICE_COMPONENT_NAME);
-        }
-    }
 }
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
index e640ce5..17fe15c 100644
--- a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
@@ -16,13 +16,17 @@
 
 package android.hardware.devicestate;
 
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 
@@ -40,7 +44,6 @@
 import androidx.annotation.Nullable;
 import androidx.test.filters.SmallTest;
 
-import com.android.internal.util.ConcurrentUtils;
 import com.android.window.flags.Flags;
 
 import org.junit.Before;
@@ -52,6 +55,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.Executor;
 
 import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
 import platform.test.runner.parameterized.Parameters;
@@ -103,7 +107,7 @@
                 permissionEnforcer, true /* simulatePostCallback */);
         final DeviceStateManagerGlobal dsmGlobal = new DeviceStateManagerGlobal(service);
         final DeviceStateCallback callback = mock(DeviceStateCallback.class);
-        dsmGlobal.registerDeviceStateCallback(callback, ConcurrentUtils.DIRECT_EXECUTOR);
+        dsmGlobal.registerDeviceStateCallback(callback, DIRECT_EXECUTOR);
 
         verify(callback, never()).onDeviceStateChanged(any());
 
@@ -120,49 +124,68 @@
         final IDeviceStateManager service = new TestDeviceStateManagerService(permissionEnforcer);
         final DeviceStateManagerGlobal dsmGlobal = new DeviceStateManagerGlobal(service);
         final DeviceStateCallback callback = mock(DeviceStateCallback.class);
-        dsmGlobal.registerDeviceStateCallback(callback, ConcurrentUtils.DIRECT_EXECUTOR);
+        dsmGlobal.registerDeviceStateCallback(callback, DIRECT_EXECUTOR);
 
         verify(callback).onDeviceStateChanged(eq(DEFAULT_DEVICE_STATE));
     }
 
     @Test
-    public void registerCallback() {
+    public void registerCallback_usesExecutorForCallbacks() {
+        final DeviceStateCallback callback = mock(DeviceStateCallback.class);
+        final Executor executor = mock(Executor.class);
+        doAnswer(invocation -> {
+            Runnable runnable = (Runnable) invocation.getArguments()[0];
+            runnable.run();
+            return null;
+        }).when(executor).execute(any(Runnable.class));
+
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback, executor);
+        mService.setBaseState(OTHER_DEVICE_STATE);
+        mService.setSupportedStates(List.of(OTHER_DEVICE_STATE));
+
+        // Verify that the given executor is used for both initial and subsequent callbacks.
+        verify(executor, times(4)).execute(any(Runnable.class));
+    }
+
+    @Test
+    public void registerCallback_supportedStatesChanged() {
         final DeviceStateCallback callback1 = mock(DeviceStateCallback.class);
         final DeviceStateCallback callback2 = mock(DeviceStateCallback.class);
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback1, DIRECT_EXECUTOR);
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback2, DIRECT_EXECUTOR);
 
-        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback1,
-                ConcurrentUtils.DIRECT_EXECUTOR);
-        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback2,
-                ConcurrentUtils.DIRECT_EXECUTOR);
-
-        // Verify initial callbacks
-        verify(callback1).onSupportedStatesChanged(eq(mService.getSupportedDeviceStates()));
-        verify(callback1).onDeviceStateChanged(eq(mService.getMergedState()));
-        verify(callback2).onDeviceStateChanged(eq(mService.getMergedState()));
-
-        reset(callback1);
-        reset(callback2);
-
-        // Change the supported states and verify callback
+        // Change the supported states and verify callback.
         mService.setSupportedStates(List.of(DEFAULT_DEVICE_STATE));
+
         verify(callback1).onSupportedStatesChanged(eq(mService.getSupportedDeviceStates()));
         verify(callback2).onSupportedStatesChanged(eq(mService.getSupportedDeviceStates()));
+    }
+
+    @Test
+    public void registerCallback_baseStateChanged() {
+        final DeviceStateCallback callback1 = mock(DeviceStateCallback.class);
+        final DeviceStateCallback callback2 = mock(DeviceStateCallback.class);
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback1, DIRECT_EXECUTOR);
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback2, DIRECT_EXECUTOR);
         mService.setSupportedStates(List.of(DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE));
 
-        reset(callback1);
-        reset(callback2);
-
-        // Change the base state and verify callback
+        // Change the base state and verify callback.
         mService.setBaseState(OTHER_DEVICE_STATE);
+
         verify(callback1).onDeviceStateChanged(eq(mService.getMergedState()));
         verify(callback2).onDeviceStateChanged(eq(mService.getMergedState()));
+    }
 
-        reset(callback1);
-        reset(callback2);
-
-        // Change the requested state and verify callback
+    @Test
+    public void registerCallback_requestedStateChanged() {
+        final DeviceStateCallback callback1 = mock(DeviceStateCallback.class);
+        final DeviceStateCallback callback2 = mock(DeviceStateCallback.class);
         final DeviceStateRequest request =
                 DeviceStateRequest.newBuilder(DEFAULT_DEVICE_STATE.getIdentifier()).build();
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback1, DIRECT_EXECUTOR);
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback2, DIRECT_EXECUTOR);
+
+        // Change the requested state and verify callback.
         mDeviceStateManagerGlobal.requestState(request, null /* executor */, null /* callback */);
 
         verify(callback1).onDeviceStateChanged(eq(mService.getMergedState()));
@@ -173,8 +196,7 @@
     public void unregisterCallback() {
         final DeviceStateCallback callback = mock(DeviceStateCallback.class);
 
-        mDeviceStateManagerGlobal
-                .registerDeviceStateCallback(callback, ConcurrentUtils.DIRECT_EXECUTOR);
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback, DIRECT_EXECUTOR);
 
         // Verify initial callbacks
         verify(callback).onSupportedStatesChanged(eq(mService.getSupportedDeviceStates()));
@@ -191,8 +213,7 @@
     @Test
     public void submitRequest() {
         final DeviceStateCallback callback = mock(DeviceStateCallback.class);
-        mDeviceStateManagerGlobal
-                .registerDeviceStateCallback(callback, ConcurrentUtils.DIRECT_EXECUTOR);
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback, DIRECT_EXECUTOR);
 
         verify(callback).onDeviceStateChanged(eq(mService.getBaseState()));
         reset(callback);
@@ -212,8 +233,7 @@
     @Test
     public void submitBaseStateOverrideRequest() {
         final DeviceStateCallback callback = mock(DeviceStateCallback.class);
-        mDeviceStateManagerGlobal
-                .registerDeviceStateCallback(callback, ConcurrentUtils.DIRECT_EXECUTOR);
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback, DIRECT_EXECUTOR);
 
         verify(callback).onDeviceStateChanged(eq(mService.getBaseState()));
         reset(callback);
@@ -234,8 +254,7 @@
     @Test
     public void submitBaseAndEmulatedStateOverride() {
         final DeviceStateCallback callback = mock(DeviceStateCallback.class);
-        mDeviceStateManagerGlobal
-                .registerDeviceStateCallback(callback, ConcurrentUtils.DIRECT_EXECUTOR);
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback, DIRECT_EXECUTOR);
 
         verify(callback).onDeviceStateChanged(eq(mService.getBaseState()));
         reset(callback);
@@ -275,7 +294,7 @@
         final DeviceStateRequest request =
                 DeviceStateRequest.newBuilder(OTHER_DEVICE_STATE.getIdentifier()).build();
         mDeviceStateManagerGlobal.requestState(request,
-                ConcurrentUtils.DIRECT_EXECUTOR /* executor */,
+                DIRECT_EXECUTOR /* executor */,
                 callback /* callback */);
 
         verify(callback).onRequestActivated(eq(request));
diff --git a/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java b/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java
index 1cc38de..4071057 100644
--- a/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java
+++ b/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java
@@ -16,6 +16,8 @@
 
 package android.os.vibrator.persistence;
 
+import static android.os.VibrationEffect.Composition.DELAY_TYPE_PAUSE;
+import static android.os.VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET;
 import static android.os.VibrationEffect.Composition.PRIMITIVE_CLICK;
 import static android.os.VibrationEffect.Composition.PRIMITIVE_LOW_TICK;
 import static android.os.VibrationEffect.Composition.PRIMITIVE_SPIN;
@@ -31,6 +33,7 @@
 import android.os.VibrationEffect;
 import android.os.vibrator.Flags;
 import android.os.vibrator.PrebakedSegment;
+import android.os.vibrator.PrimitiveSegment;
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
@@ -437,7 +440,7 @@
 
     @Test
     @EnableFlags(Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
-    public void testVendorEffect_featureFlagEnabled_allSucceed() throws Exception {
+    public void testVendorEffect_allSucceed() throws Exception {
         PersistableBundle vendorData = new PersistableBundle();
         vendorData.putInt("id", 1);
         vendorData.putDouble("scale", 0.5);
@@ -476,7 +479,7 @@
 
     @Test
     @EnableFlags(Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
-    public void testInvalidVendorEffect_featureFlagEnabled_allFail() throws IOException {
+    public void testInvalidVendorEffect_allFail() throws IOException {
         String emptyTag = "<vibration-effect><vendor-effect/></vibration-effect>";
         assertPublicApisParserFails(emptyTag);
         assertHiddenApisParserFails(emptyTag);
@@ -526,6 +529,81 @@
         assertHiddenApisSerializerFails(vendorEffect);
     }
 
+    @Test
+    @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void testPrimitiveDelayType_allSucceed() throws Exception {
+        VibrationEffect effect = VibrationEffect.startComposition()
+                .addPrimitive(PRIMITIVE_TICK, 1.0f, 0, DELAY_TYPE_RELATIVE_START_OFFSET)
+                .addPrimitive(PRIMITIVE_CLICK, 0.123f, 10, DELAY_TYPE_PAUSE)
+                .compose();
+        String xml = """
+                <vibration-effect>
+                    <primitive-effect name="tick" delayType="relative_start_offset"/>
+                    <primitive-effect name="click" scale="0.123" delayMs="10"/>
+                </vibration-effect>
+                """;
+
+        assertPublicApisParserSucceeds(xml, effect);
+        assertPublicApisSerializerSucceeds(effect, "tick", "click");
+        // Delay type pause is not serialized, as it's the default one
+        assertPublicApisSerializerSucceeds(effect, "relative_start_offset", "click");
+        assertPublicApisRoundTrip(effect);
+
+        assertHiddenApisParserSucceeds(xml, effect);
+        assertHiddenApisSerializerSucceeds(effect, "tick", "click");
+        assertHiddenApisRoundTrip(effect);
+
+        // Check PersistableBundle from round-trip
+        VibrationEffect.Composed parsedEffect = ((VibrationEffect.Composed) parseVibrationEffect(
+                serialize(effect), /* flags= */ 0));
+        assertThat(parsedEffect.getRepeatIndex()).isEqualTo(-1);
+        assertThat(parsedEffect.getSegments()).containsExactly(
+                new PrimitiveSegment(PRIMITIVE_TICK, 1.0f, 0, DELAY_TYPE_RELATIVE_START_OFFSET),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 0.123f, 10, DELAY_TYPE_PAUSE))
+                .inOrder();
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void testPrimitiveInvalidDelayType_allFail() {
+        String emptyAttribute = """
+                <vibration-effect>
+                    <primitive-effect name="tick" delayType=""/>
+                </vibration-effect>
+                """;
+        assertPublicApisParserFails(emptyAttribute);
+        assertHiddenApisParserFails(emptyAttribute);
+
+        String invalidString = """
+                <vibration-effect>
+                    <primitive-effect name="tick" delayType="invalid"/>
+                </vibration-effect>
+                """;
+        assertPublicApisParserFails(invalidString);
+        assertHiddenApisParserFails(invalidString);
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void testPrimitiveDelayType_featureFlagDisabled_allFail() {
+        VibrationEffect effect = VibrationEffect.startComposition()
+                .addPrimitive(PRIMITIVE_TICK, 1.0f, 0, DELAY_TYPE_RELATIVE_START_OFFSET)
+                .addPrimitive(PRIMITIVE_CLICK, 0.123f, 10, DELAY_TYPE_PAUSE)
+                .compose();
+        String xml = """
+                <vibration-effect>
+                    <primitive-effect name="tick" delayType="relative_start_offset"/>
+                    <primitive-effect name="click" scale="0.123" delayMs="10" delayType="pause"/>
+                </vibration-effect>
+                """;
+
+        assertPublicApisParserFails(xml);
+        assertPublicApisSerializerFails(effect);
+
+        assertHiddenApisParserFails(xml);
+        assertHiddenApisSerializerFails(effect);
+    }
+
     private void assertPublicApisParserFails(String xml) {
         assertThrows("Expected parseVibrationEffect to fail for " + xml,
                 VibrationXmlParser.ParseFailedException.class,
diff --git a/core/xsd/permission.xsd b/core/xsd/permission.xsd
index 0ec8f7d..0a0ca7c 100644
--- a/core/xsd/permission.xsd
+++ b/core/xsd/permission.xsd
@@ -43,6 +43,7 @@
                 <xs:element name="disabled-until-used-preinstalled-carrier-app" type="disabled-until-used-preinstalled-carrier-app"/>
                 <xs:element name="privapp-permissions" type="privapp-permissions"/>
                 <xs:element name="oem-permissions" type="oem-permissions"/>
+                <xs:element name="signature-permissions" type="signature-permissions"/>
                 <xs:element name="hidden-api-whitelisted-app" type="hidden-api-whitelisted-app"/>
                 <xs:element name="allow-association" type="allow-association"/>
                 <xs:element name="bugreport-whitelisted" type="bugreport-whitelisted"/>
@@ -156,6 +157,21 @@
         </xs:sequence>
         <xs:attribute name="package" type="xs:string"/>
     </xs:complexType>
+    <xs:complexType name="signature-permissions">
+        <xs:sequence>
+            <xs:element name="permission" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:attribute name="name" type="xs:string"/>
+                </xs:complexType>
+            </xs:element>
+            <xs:element name="deny-permission" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:attribute name="name" type="xs:string"/>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+        <xs:attribute name="package" type="xs:string"/>
+    </xs:complexType>
     <xs:complexType name="hidden-api-whitelisted-app">
         <xs:attribute name="package" type="xs:string"/>
     </xs:complexType>
diff --git a/core/xsd/schema/current.txt b/core/xsd/schema/current.txt
index f3beea1..cdec6ab 100644
--- a/core/xsd/schema/current.txt
+++ b/core/xsd/schema/current.txt
@@ -183,6 +183,7 @@
     method public java.util.List<com.android.xml.permission.configfile.OemPermissions> getOemPermissions_optional();
     method public java.util.List<com.android.xml.permission.configfile.Permission> getPermission_optional();
     method public java.util.List<com.android.xml.permission.configfile.PrivappPermissions> getPrivappPermissions_optional();
+    method public java.util.List<com.android.xml.permission.configfile.SignaturePermissions> getSignaturePermissions_optional();
     method public java.util.List<com.android.xml.permission.configfile.SplitPermission> getSplitPermission_optional();
     method public java.util.List<com.android.xml.permission.configfile.SystemUserBlacklistedApp> getSystemUserBlacklistedApp_optional();
     method public java.util.List<com.android.xml.permission.configfile.SystemUserWhitelistedApp> getSystemUserWhitelistedApp_optional();
@@ -209,6 +210,26 @@
     method public void setName(String);
   }
 
+  public class SignaturePermissions {
+    ctor public SignaturePermissions();
+    method public java.util.List<com.android.xml.permission.configfile.SignaturePermissions.DenyPermission> getDenyPermission();
+    method public java.util.List<com.android.xml.permission.configfile.SignaturePermissions.Permission> getPermission();
+    method public String get_package();
+    method public void set_package(String);
+  }
+
+  public static class SignaturePermissions.DenyPermission {
+    ctor public SignaturePermissions.DenyPermission();
+    method public String getName();
+    method public void setName(String);
+  }
+
+  public static class SignaturePermissions.Permission {
+    ctor public SignaturePermissions.Permission();
+    method public String getName();
+    method public void setName(String);
+  }
+
   public class SplitPermission {
     ctor public SplitPermission();
     method public java.util.List<com.android.xml.permission.configfile.SplitPermission.Library> getLibrary();
diff --git a/core/xsd/vibrator/vibration/schema/current.txt b/core/xsd/vibrator/vibration/schema/current.txt
index 280b405..b4148d6 100644
--- a/core/xsd/vibrator/vibration/schema/current.txt
+++ b/core/xsd/vibrator/vibration/schema/current.txt
@@ -15,12 +15,20 @@
     enum_constant public static final com.android.internal.vibrator.persistence.PredefinedEffectName tick;
   }
 
+  public enum PrimitiveDelayType {
+    method public String getRawName();
+    enum_constant public static final com.android.internal.vibrator.persistence.PrimitiveDelayType pause;
+    enum_constant public static final com.android.internal.vibrator.persistence.PrimitiveDelayType relative_start_offset;
+  }
+
   public class PrimitiveEffect {
     ctor public PrimitiveEffect();
     method public java.math.BigInteger getDelayMs();
+    method public com.android.internal.vibrator.persistence.PrimitiveDelayType getDelayType();
     method public com.android.internal.vibrator.persistence.PrimitiveEffectName getName();
     method public float getScale();
     method public void setDelayMs(java.math.BigInteger);
+    method public void setDelayType(com.android.internal.vibrator.persistence.PrimitiveDelayType);
     method public void setName(com.android.internal.vibrator.persistence.PrimitiveEffectName);
     method public void setScale(float);
   }
diff --git a/core/xsd/vibrator/vibration/vibration-plus-hidden-apis.xsd b/core/xsd/vibrator/vibration/vibration-plus-hidden-apis.xsd
index 21a6fac..910a9b7 100644
--- a/core/xsd/vibrator/vibration/vibration-plus-hidden-apis.xsd
+++ b/core/xsd/vibrator/vibration/vibration-plus-hidden-apis.xsd
@@ -147,6 +147,7 @@
         <xs:attribute name="name" type="PrimitiveEffectName" use="required"/>
         <xs:attribute name="scale" type="PrimitiveScale"/>
         <xs:attribute name="delayMs" type="xs:nonNegativeInteger"/>
+        <xs:attribute name="delayType" type="PrimitiveDelayType"/>
     </xs:complexType>
 
     <!-- Primitive names as defined by VibrationEffect.Composition.PRIMITIVE_* -->
@@ -171,4 +172,12 @@
         </xs:restriction>
     </xs:simpleType>
 
+    <!-- Primitive delay types VibrationEffect.Composition.DELAY_TYPE_* -->
+    <xs:simpleType  name="PrimitiveDelayType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="pause"/>
+            <xs:enumeration value="relative_start_offset"/>
+        </xs:restriction>
+    </xs:simpleType>
+
 </xs:schema>
diff --git a/core/xsd/vibrator/vibration/vibration.xsd b/core/xsd/vibrator/vibration/vibration.xsd
index d35d777..3c8e016 100644
--- a/core/xsd/vibrator/vibration/vibration.xsd
+++ b/core/xsd/vibrator/vibration/vibration.xsd
@@ -124,6 +124,7 @@
         <xs:attribute name="name" type="PrimitiveEffectName" use="required"/>
         <xs:attribute name="scale" type="PrimitiveScale"/>
         <xs:attribute name="delayMs" type="xs:nonNegativeInteger"/>
+        <xs:attribute name="delayType" type="PrimitiveDelayType"/>
     </xs:complexType>
 
     <!-- Primitive names as defined by VibrationEffect.Composition.PRIMITIVE_* -->
@@ -148,4 +149,12 @@
         </xs:restriction>
     </xs:simpleType>
 
+    <!-- Primitive delay types VibrationEffect.Composition.DELAY_TYPE_* -->
+    <xs:simpleType  name="PrimitiveDelayType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="pause"/>
+            <xs:enumeration value="relative_start_offset"/>
+        </xs:restriction>
+    </xs:simpleType>
+
 </xs:schema>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index ba1407c..897fc54 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -599,7 +599,7 @@
         <!-- Permission required for CTS test - CtsAppTestCases -->
         <permission name="android.permission.KILL_UID" />
         <!-- Permission required for CTS test - AdvancedProtectionManagerTest -->
-        <permission name="android.permission.SET_ADVANCED_PROTECTION_MODE" />
+        <permission name="android.permission.MANAGE_ADVANCED_PROTECTION_MODE" />
         <permission name="android.permission.QUERY_ADVANCED_PROTECTION_MODE" />
         <!-- Permissions required for CTS test - SettingsPreferenceServiceClientTest -->
         <permission name="android.permission.READ_SYSTEM_PREFERENCES" />
@@ -677,8 +677,4 @@
         <permission name="android.permission.BATTERY_STATS"/>
         <permission name="android.permission.ENTER_TRADE_IN_MODE"/>
     </privapp-permissions>
-
-    <privapp-permissions package="com.android.multiuser">
-        <permission name="android.permission.MANAGE_USERS"/>
-    </privapp-permissions>
 </permissions>
diff --git a/errorprone/Android.bp b/errorprone/Android.bp
index b559a15..1428b89 100644
--- a/errorprone/Android.bp
+++ b/errorprone/Android.bp
@@ -31,6 +31,14 @@
         "//external/auto:auto_service_annotations",
     ],
 
+    javacflags: [
+        // These exports are needed because this errorprone plugin access some private classes
+        // of the java compiler.
+        "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
+        "--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
+        "--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
+    ],
+
     plugins: [
         "//external/auto:auto_service_plugin",
     ],
diff --git a/framework-jarjar-rules.txt b/framework-jarjar-rules.txt
index 6339a87..087378b 100644
--- a/framework-jarjar-rules.txt
+++ b/framework-jarjar-rules.txt
@@ -4,7 +4,6 @@
 
 # Framework-specific renames.
 rule android.net.wifi.WifiAnnotations* android.internal.wifi.WifiAnnotations@1
-rule com.android.server.vcn.util.** com.android.server.vcn.repackaged.util.@1
 
 # for modules-utils-build dependency
 rule com.android.modules.utils.build.** android.internal.modules.utils.build.@1
diff --git a/graphics/java/android/graphics/RuntimeColorFilter.java b/graphics/java/android/graphics/RuntimeColorFilter.java
index d112f71..a64acfe 100644
--- a/graphics/java/android/graphics/RuntimeColorFilter.java
+++ b/graphics/java/android/graphics/RuntimeColorFilter.java
@@ -280,7 +280,8 @@
         if (colorFilter == null) {
             throw new NullPointerException("The colorFilter parameter must not be null");
         }
-        nativeUpdateChild(getNativeInstance(), filterName, colorFilter.getNativeInstance());
+        nativeUpdateInputColorFilter(getNativeInstance(), filterName,
+                colorFilter.getNativeInstance());
     }
 
     /**
@@ -318,5 +319,6 @@
             long colorFilter, String uniformName, int value1, int value2, int value3,
             int value4, int count);
     private static native void nativeUpdateChild(long colorFilter, String childName, long child);
-
+    private static native void nativeUpdateInputColorFilter(long colorFilter, String childName,
+            long inputFilter);
 }
diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java
index 6316c1f..3543e99 100644
--- a/graphics/java/android/graphics/RuntimeShader.java
+++ b/graphics/java/android/graphics/RuntimeShader.java
@@ -264,6 +264,9 @@
      * enable better heap tracking & tooling support
      */
     private ArrayMap<String, Shader> mShaderUniforms = new ArrayMap<>();
+    private ArrayMap<String, ColorFilter> mColorFilterUniforms = new ArrayMap<>();
+    private ArrayMap<String, RuntimeXfermode> mXfermodeUniforms = new ArrayMap<>();
+
 
     /**
      * Creates a new RuntimeShader.
@@ -544,8 +547,10 @@
         if (colorFilter == null) {
             throw new NullPointerException("The colorFilter parameter must not be null");
         }
-        nativeUpdateChild(mNativeInstanceRuntimeShaderBuilder, filterName,
+        mColorFilterUniforms.put(filterName, colorFilter);
+        nativeUpdateColorFilter(mNativeInstanceRuntimeShaderBuilder, filterName,
                 colorFilter.getNativeInstance());
+        discardNativeInstance();
     }
 
     /**
@@ -563,8 +568,10 @@
         if (xfermode == null) {
             throw new NullPointerException("The xfermode parameter must not be null");
         }
+        mXfermodeUniforms.put(xfermodeName, xfermode);
         nativeUpdateChild(mNativeInstanceRuntimeShaderBuilder, xfermodeName,
                 xfermode.createNativeInstance());
+        discardNativeInstance();
     }
 
 
@@ -594,6 +601,8 @@
             int value4, int count);
     private static native void nativeUpdateShader(
             long shaderBuilder, String shaderName, long shader);
+    private static native void nativeUpdateColorFilter(
+            long shaderBuilder, String colorFilterName, long colorFilter);
     private static native void nativeUpdateChild(
             long shaderBuilder, String childName, long child);
 }
diff --git a/graphics/java/android/graphics/RuntimeXfermode.java b/graphics/java/android/graphics/RuntimeXfermode.java
index 51d97a4..c8a0b1a 100644
--- a/graphics/java/android/graphics/RuntimeXfermode.java
+++ b/graphics/java/android/graphics/RuntimeXfermode.java
@@ -285,7 +285,8 @@
         if (colorFilter == null) {
             throw new NullPointerException("The colorFilter parameter must not be null");
         }
-        nativeUpdateChild(mBuilderNativeInstance, filterName, colorFilter.getNativeInstance());
+        nativeUpdateColorFilter(mBuilderNativeInstance, filterName,
+                colorFilter.getNativeInstance());
     }
 
     /**
@@ -325,5 +326,6 @@
             long builder, String uniformName, int value1, int value2, int value3,
             int value4, int count);
     private static native void nativeUpdateChild(long builder, String childName, long child);
+    private static native void nativeUpdateColorFilter(long builder, String childName, long filter);
 
 }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
index 0896138..223f9f6 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
@@ -26,12 +26,12 @@
 import android.hardware.devicestate.DeviceStateManager;
 import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
 import android.hardware.devicestate.DeviceStateUtil;
+import android.os.Looper;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseIntArray;
 
 import androidx.annotation.BinderThread;
-import androidx.annotation.GuardedBy;
 import androidx.annotation.MainThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
@@ -39,7 +39,6 @@
 import androidx.window.common.layout.DisplayFoldFeatureCommon;
 
 import com.android.internal.R;
-import com.android.window.flags.Flags;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -70,19 +69,10 @@
      * "rear display". Concurrent mode for example is activated via public API and can be active in
      * both the "open" and "half folded" device states.
      */
-    // TODO: b/337820752 - Add @GuardedBy("mCurrentDeviceStateLock") after flag cleanup.
     private DeviceState mCurrentDeviceState = INVALID_DEVICE_STATE;
 
-    /**
-     * Lock to synchronize access to {@link #mCurrentDeviceState}.
-     *
-     * <p>This lock is used to ensure thread-safety when accessing and modifying the
-     * {@link #mCurrentDeviceState} field. It is acquired by both the binder thread (if
-     * {@link Flags#wlinfoOncreate()} is enabled) and the main thread (if
-     * {@link Flags#wlinfoOncreate()} is disabled) to prevent race conditions and
-     * ensure data consistency.
-     */
-    private final Object mCurrentDeviceStateLock = new Object();
+    @NonNull
+    private final Context mContext;
 
     @NonNull
     private final RawFoldingFeatureProducer mRawFoldSupplier;
@@ -90,38 +80,40 @@
     @NonNull
     private final DeviceStateMapper mDeviceStateMapper;
 
-    @VisibleForTesting
-    final DeviceStateCallback mDeviceStateCallback = new DeviceStateCallback() {
-        // The GuardedBy analysis is intra-procedural, meaning it doesn’t consider the getData()
-        // implementation. See https://errorprone.info/bugpattern/GuardedBy for limitations.
-        @SuppressWarnings("GuardedBy")
-        @BinderThread // When Flags.wlinfoOncreate() is enabled.
-        @MainThread // When Flags.wlinfoOncreate() is disabled.
+    private final DeviceStateCallback mDeviceStateCallback = new DeviceStateCallback() {
+        @BinderThread // Subsequent callback after registered.
+        @MainThread // Initial callback if registration is on the main thread.
         @Override
         public void onDeviceStateChanged(@NonNull DeviceState state) {
-            synchronized (mCurrentDeviceStateLock) {
-                mCurrentDeviceState = state;
-                mRawFoldSupplier.getData(DeviceStateManagerFoldingFeatureProducer.this
-                        ::notifyFoldingFeatureChangeLocked);
-            }
+            final boolean isMainThread = Looper.myLooper() == Looper.getMainLooper();
+            final Executor executor = isMainThread ? Runnable::run : mContext.getMainExecutor();
+            executor.execute(() -> {
+                DeviceStateManagerFoldingFeatureProducer.this.onDeviceStateChanged(state);
+            });
         }
     };
 
     public DeviceStateManagerFoldingFeatureProducer(@NonNull Context context,
             @NonNull RawFoldingFeatureProducer rawFoldSupplier,
             @NonNull DeviceStateManager deviceStateManager) {
+        mContext = context;
         mRawFoldSupplier = rawFoldSupplier;
         mDeviceStateMapper =
                 new DeviceStateMapper(context, deviceStateManager.getSupportedDeviceStates());
 
         if (!mDeviceStateMapper.isDeviceStateToPostureMapEmpty()) {
-            final Executor executor =
-                    Flags.wlinfoOncreate() ? Runnable::run : context.getMainExecutor();
             Objects.requireNonNull(deviceStateManager)
-                    .registerCallback(executor, mDeviceStateCallback);
+                    .registerCallback(Runnable::run, mDeviceStateCallback);
         }
     }
 
+    @MainThread
+    @VisibleForTesting
+    void onDeviceStateChanged(@NonNull DeviceState state) {
+        mCurrentDeviceState = state;
+        mRawFoldSupplier.getData(this::notifyFoldingFeatureChangeLocked);
+    }
+
     /**
      * Add a callback to mCallbacks if there is no device state. This callback will be run
      * once a device state is set. Otherwise,run the callback immediately.
@@ -139,27 +131,20 @@
         }
     }
 
-    // The GuardedBy analysis is intra-procedural, meaning it doesn’t consider the implementation of
-    // addDataChangedCallback(). See https://errorprone.info/bugpattern/GuardedBy for limitations.
-    @SuppressWarnings("GuardedBy")
     @Override
     protected void onListenersChanged() {
         super.onListenersChanged();
-        synchronized (mCurrentDeviceStateLock) {
-            if (hasListeners()) {
-                mRawFoldSupplier.addDataChangedCallback(this::notifyFoldingFeatureChangeLocked);
-            } else {
-                mCurrentDeviceState = INVALID_DEVICE_STATE;
-                mRawFoldSupplier.removeDataChangedCallback(this::notifyFoldingFeatureChangeLocked);
-            }
+        if (hasListeners()) {
+            mRawFoldSupplier.addDataChangedCallback(this::notifyFoldingFeatureChangeLocked);
+        } else {
+            mCurrentDeviceState = INVALID_DEVICE_STATE;
+            mRawFoldSupplier.removeDataChangedCallback(this::notifyFoldingFeatureChangeLocked);
         }
     }
 
     @NonNull
     private DeviceState getCurrentDeviceState() {
-        synchronized (mCurrentDeviceStateLock) {
-            return mCurrentDeviceState;
-        }
+        return mCurrentDeviceState;
     }
 
     @NonNull
@@ -231,7 +216,6 @@
         });
     }
 
-    @GuardedBy("mCurrentDeviceStateLock")
     private void notifyFoldingFeatureChangeLocked(String displayFeaturesString) {
         final DeviceState state = mCurrentDeviceState;
         if (!mDeviceStateMapper.isDeviceStateValid(state)) {
@@ -252,29 +236,16 @@
         return parseListFromString(displayFeaturesString, hingeState);
     }
 
-    /**
-     * Internal class to map device states to corresponding postures.
-     *
-     * <p>This class encapsulates the logic for mapping device states to postures. The mapping is
-     * immutable after initialization to ensure thread safety.
-     */
+    /** Internal class to map device states to corresponding postures. */
     private static class DeviceStateMapper {
         /**
          * Emulated device state
          * {@link DeviceStateManager.DeviceStateCallback#onDeviceStateChanged(DeviceState)} to
          * {@link CommonFoldingFeature.State} map.
-         *
-         * <p>This map must be immutable after initialization to ensure thread safety, as it may be
-         * accessed from multiple threads. Modifications should only occur during object
-         * construction.
          */
         private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray();
 
-        /**
-         * The list of device states that are supported.
-         *
-         * <p>This list must be immutable after initialization to ensure thread safety.
-         */
+        /** The list of device states that are supported. */
         @NonNull
         private final List<DeviceState> mSupportedStates;
 
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index 6928409..a5a84db 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -182,8 +182,15 @@
 
     @NonNull
     List<ParcelableSplitContainerData> getParcelableSplitContainerDataList() {
-        final List<ParcelableSplitContainerData> data = new ArrayList<>(mSplitContainers.size());
+        final int size =
+                mSplitPinContainer != null ? mSplitContainers.size() - 1 : mSplitContainers.size();
+        final List<ParcelableSplitContainerData> data = new ArrayList<>(size);
         for (SplitContainer splitContainer : mSplitContainers) {
+            if (splitContainer == mSplitPinContainer) {
+                // Skip SplitPinContainer as it cannot be restored because the SplitPinRule is
+                // set while pinning the container in runtime.
+                continue;
+            }
             data.add(splitContainer.getParcelableData());
         }
         return data;
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducerTest.kt b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducerTest.kt
index 90887a7..ad29bf6 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducerTest.kt
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducerTest.kt
@@ -20,10 +20,8 @@
 import android.content.res.Resources
 import android.hardware.devicestate.DeviceState
 import android.hardware.devicestate.DeviceStateManager
-import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
-import android.platform.test.flag.junit.SetFlagsRule
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
 import androidx.window.common.layout.CommonFoldingFeature
 import androidx.window.common.layout.CommonFoldingFeature.COMMON_STATE_FLAT
 import androidx.window.common.layout.CommonFoldingFeature.COMMON_STATE_HALF_OPENED
@@ -34,19 +32,16 @@
 import androidx.window.common.layout.DisplayFoldFeatureCommon.DISPLAY_FOLD_FEATURE_PROPERTY_SUPPORTS_HALF_OPENED
 import androidx.window.common.layout.DisplayFoldFeatureCommon.DISPLAY_FOLD_FEATURE_TYPE_SCREEN_FOLD_IN
 import com.android.internal.R
-import com.android.window.flags.Flags
 import com.google.common.truth.Truth.assertThat
 import java.util.Optional
 import java.util.concurrent.Executor
 import java.util.function.Consumer
-import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
 import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
 import org.mockito.kotlin.doAnswer
 import org.mockito.kotlin.doReturn
-import org.mockito.kotlin.eq
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.never
 import org.mockito.kotlin.stub
@@ -60,9 +55,6 @@
  */
 @RunWith(AndroidJUnit4::class)
 class DeviceStateManagerFoldingFeatureProducerTest {
-    @get:Rule
-    val setFlagsRule: SetFlagsRule = SetFlagsRule()
-
     private val mMockDeviceStateManager = mock<DeviceStateManager>()
     private val mMockResources = mock<Resources> {
         on { getStringArray(R.array.config_device_state_postures) } doReturn DEVICE_STATE_POSTURES
@@ -79,32 +71,39 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_WLINFO_ONCREATE)
-    fun testRegisterCallback_whenWlinfoOncreateIsDisabled_usesMainExecutor() {
+    fun testRegisterCallback_initialCallbackOnMainThread_executesDirectly() {
         DeviceStateManagerFoldingFeatureProducer(
             mMockContext,
             mRawFoldSupplier,
             mMockDeviceStateManager,
         )
+        val callbackCaptor = argumentCaptor<DeviceStateManager.DeviceStateCallback>()
+        verify(mMockDeviceStateManager).registerCallback(any(), callbackCaptor.capture())
 
-        verify(mMockDeviceStateManager).registerCallback(eq(mMockContext.mainExecutor), any())
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            callbackCaptor.firstValue.onDeviceStateChanged(DEVICE_STATE_HALF_OPENED)
+        }
+
+        verify(mMockContext, never()).getMainExecutor()
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_WLINFO_ONCREATE)
-    fun testRegisterCallback_whenWlinfoOncreateIsEnabled_usesRunnableRun() {
-        val executorCaptor = ArgumentCaptor.forClass(Executor::class.java)
-        val runnable = mock<Runnable>()
-
+    fun testRegisterCallback_subsequentCallbacks_postsToMainThread() {
+        val mockMainExecutor = mock<Executor>()
+        mMockContext.stub {
+            on { getMainExecutor() } doReturn mockMainExecutor
+        }
         DeviceStateManagerFoldingFeatureProducer(
             mMockContext,
             mRawFoldSupplier,
             mMockDeviceStateManager,
         )
+        val callbackCaptor = argumentCaptor<DeviceStateManager.DeviceStateCallback>()
+        verify(mMockDeviceStateManager).registerCallback(any(), callbackCaptor.capture())
 
-        verify(mMockDeviceStateManager).registerCallback(executorCaptor.capture(), any())
-        executorCaptor.value.execute(runnable)
-        verify(runnable).run()
+        callbackCaptor.firstValue.onDeviceStateChanged(DEVICE_STATE_HALF_OPENED)
+
+        verify(mockMainExecutor).execute(any())
     }
 
     @Test
@@ -114,7 +113,7 @@
             mRawFoldSupplier,
             mMockDeviceStateManager,
         )
-        ffp.mDeviceStateCallback.onDeviceStateChanged(DEVICE_STATE_HALF_OPENED)
+        ffp.onDeviceStateChanged(DEVICE_STATE_HALF_OPENED)
 
         val currentData = ffp.getCurrentData()
 
@@ -237,7 +236,7 @@
             mRawFoldSupplier,
             mMockDeviceStateManager,
         )
-        ffp.mDeviceStateCallback.onDeviceStateChanged(DEVICE_STATE_HALF_OPENED)
+        ffp.onDeviceStateChanged(DEVICE_STATE_HALF_OPENED)
         val storeFeaturesConsumer = mock<Consumer<List<CommonFoldingFeature>>>()
 
         ffp.getData(storeFeaturesConsumer)
@@ -257,8 +256,8 @@
         ffp.getData(storeFeaturesConsumer)
 
         verify(storeFeaturesConsumer, never()).accept(any())
-        ffp.mDeviceStateCallback.onDeviceStateChanged(DEVICE_STATE_HALF_OPENED)
-        ffp.mDeviceStateCallback.onDeviceStateChanged(DEVICE_STATE_OPENED)
+        ffp.onDeviceStateChanged(DEVICE_STATE_HALF_OPENED)
+        ffp.onDeviceStateChanged(DEVICE_STATE_OPENED)
         verify(storeFeaturesConsumer).accept(HALF_OPENED_FOLDING_FEATURES)
     }
 
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index a354bf7..4c75ea4 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -182,6 +182,7 @@
         "kotlinx-coroutines-core",
         "//frameworks/libs/systemui:com_android_systemui_shared_flags_lib",
         "//frameworks/libs/systemui:iconloader_base",
+        "com_android_launcher3_flags_lib",
         "com_android_wm_shell_flags_lib",
         "PlatformAnimationLib",
         "WindowManager-Shell-proto",
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt
new file mode 100644
index 0000000..f535fbd
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt
@@ -0,0 +1,320 @@
+/*
+ * 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.bubbles
+
+import android.content.Context
+import android.content.pm.LauncherApps
+import android.graphics.Insets
+import android.graphics.Rect
+import android.os.Handler
+import android.os.UserManager
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import android.view.IWindowManager
+import android.view.WindowManager
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.internal.protolog.ProtoLog
+import com.android.internal.statusbar.IStatusBarService
+import com.android.wm.shell.Flags
+import com.android.wm.shell.ShellTaskOrganizer
+import com.android.wm.shell.WindowManagerShellWrapper
+import com.android.wm.shell.bubbles.Bubbles.SysuiProxy
+import com.android.wm.shell.bubbles.properties.ProdBubbleProperties
+import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayInsetsController
+import com.android.wm.shell.common.FloatingContentCoordinator
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.common.SyncTransactionQueue
+import com.android.wm.shell.common.TaskStackListenerImpl
+import com.android.wm.shell.draganddrop.DragAndDropController
+import com.android.wm.shell.shared.TransactionPool
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
+import com.android.wm.shell.shared.bubbles.BubbleBarUpdate
+import com.android.wm.shell.sysui.ShellCommandHandler
+import com.android.wm.shell.sysui.ShellController
+import com.android.wm.shell.sysui.ShellInit
+import com.android.wm.shell.taskview.TaskViewTransitions
+import com.android.wm.shell.transition.Transitions
+import com.google.common.truth.Truth.assertThat
+import com.google.common.util.concurrent.MoreExecutors.directExecutor
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+import java.util.Optional
+
+/** Tests for [BubbleController] when using bubble bar */
+@SmallTest
+@EnableFlags(Flags.FLAG_ENABLE_BUBBLE_BAR)
+@RunWith(AndroidJUnit4::class)
+class BubbleControllerBubbleBarTest {
+
+    companion object {
+        private const val SCREEN_WIDTH = 2000
+        private const val SCREEN_HEIGHT = 1000
+    }
+
+    @get:Rule val setFlagsRule = SetFlagsRule()
+
+    private val context = ApplicationProvider.getApplicationContext<Context>()
+
+    private lateinit var bubbleController: BubbleController
+    private lateinit var uiEventLoggerFake: UiEventLoggerFake
+    private lateinit var bubblePositioner: BubblePositioner
+    private lateinit var bubbleData: BubbleData
+    private lateinit var mainExecutor: TestExecutor
+    private lateinit var bgExecutor: TestExecutor
+
+    @Before
+    fun setUp() {
+        ProtoLog.REQUIRE_PROTOLOGTOOL = false
+        ProtoLog.init()
+
+        mainExecutor = TestExecutor()
+        bgExecutor = TestExecutor()
+
+        uiEventLoggerFake = UiEventLoggerFake()
+        val bubbleLogger = BubbleLogger(uiEventLoggerFake)
+
+        val deviceConfig =
+            DeviceConfig(
+                windowBounds = Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT),
+                isLargeScreen = true,
+                isSmallTablet = false,
+                isLandscape = true,
+                isRtl = false,
+                insets = Insets.of(10, 20, 30, 40),
+            )
+
+        bubblePositioner = BubblePositioner(context, deviceConfig)
+        bubblePositioner.isShowingInBubbleBar = true
+
+        bubbleData =
+            BubbleData(
+                context,
+                bubbleLogger,
+                bubblePositioner,
+                BubbleEducationController(context),
+                mainExecutor,
+                bgExecutor,
+            )
+
+        val shellInit = ShellInit(mainExecutor)
+
+        bubbleController =
+            createBubbleController(
+                shellInit,
+                bubbleData,
+                bubbleLogger,
+                bubblePositioner,
+                mainExecutor,
+                bgExecutor,
+            )
+        bubbleController.asBubbles().setSysuiProxy(Mockito.mock(SysuiProxy::class.java))
+
+        shellInit.init()
+
+        mainExecutor.flushAll()
+        bgExecutor.flushAll()
+
+        bubbleController.registerBubbleStateListener(FakeBubblesStateListener())
+    }
+
+    @After
+    fun tearDown() {
+        mainExecutor.flushAll()
+        bgExecutor.flushAll()
+    }
+
+    @Test
+    fun testEventLogging_bubbleBar_dragBarLeft() {
+        addBubble()
+
+        bubblePositioner.bubbleBarLocation = BubbleBarLocation.RIGHT
+
+        bubbleController.setBubbleBarLocation(
+            BubbleBarLocation.LEFT,
+            BubbleBarLocation.UpdateSource.DRAG_BAR,
+        )
+
+        // 2 events: add bubble + drag event
+        assertThat(uiEventLoggerFake.numLogs()).isEqualTo(2)
+        assertThat(uiEventLoggerFake.eventId(1))
+            .isEqualTo(BubbleLogger.Event.BUBBLE_BAR_MOVED_LEFT_DRAG_BAR.id)
+    }
+
+    @Test
+    fun testEventLogging_bubbleBar_dragBarRight() {
+        addBubble()
+
+        bubblePositioner.bubbleBarLocation = BubbleBarLocation.LEFT
+
+        bubbleController.setBubbleBarLocation(
+            BubbleBarLocation.RIGHT,
+            BubbleBarLocation.UpdateSource.DRAG_BAR,
+        )
+
+        // 2 events: add bubble + drag event
+        assertThat(uiEventLoggerFake.numLogs()).isEqualTo(2)
+        assertThat(uiEventLoggerFake.eventId(1))
+            .isEqualTo(BubbleLogger.Event.BUBBLE_BAR_MOVED_RIGHT_DRAG_BAR.id)
+    }
+
+    @Test
+    fun testEventLogging_bubbleBar_dragBubbleLeft() {
+        addBubble()
+
+        bubblePositioner.bubbleBarLocation = BubbleBarLocation.RIGHT
+
+        bubbleController.setBubbleBarLocation(
+            BubbleBarLocation.LEFT,
+            BubbleBarLocation.UpdateSource.DRAG_BUBBLE,
+        )
+
+        // 2 events: add bubble + drag event
+        assertThat(uiEventLoggerFake.numLogs()).isEqualTo(2)
+        assertThat(uiEventLoggerFake.eventId(1))
+            .isEqualTo(BubbleLogger.Event.BUBBLE_BAR_MOVED_LEFT_DRAG_BUBBLE.id)
+    }
+
+    @Test
+    fun testEventLogging_bubbleBar_dragBubbleRight() {
+        addBubble()
+
+        bubblePositioner.bubbleBarLocation = BubbleBarLocation.LEFT
+
+        bubbleController.setBubbleBarLocation(
+            BubbleBarLocation.RIGHT,
+            BubbleBarLocation.UpdateSource.DRAG_BUBBLE,
+        )
+
+        // 2 events: add bubble + drag event
+        assertThat(uiEventLoggerFake.numLogs()).isEqualTo(2)
+        assertThat(uiEventLoggerFake.eventId(1))
+            .isEqualTo(BubbleLogger.Event.BUBBLE_BAR_MOVED_RIGHT_DRAG_BUBBLE.id)
+    }
+
+    private fun addBubble(): Bubble {
+        val bubble = FakeBubbleFactory.createChatBubble(context)
+        bubble.setInflateSynchronously(true)
+        bubbleData.notificationEntryUpdated(
+            bubble,
+            /* suppressFlyout= */ true,
+            /* showInShade= */ true,
+        )
+        return bubble
+    }
+
+    private fun createBubbleController(
+        shellInit: ShellInit,
+        bubbleData: BubbleData,
+        bubbleLogger: BubbleLogger,
+        bubblePositioner: BubblePositioner,
+        mainExecutor: TestExecutor,
+        bgExecutor: TestExecutor,
+    ): BubbleController {
+        val shellCommandHandler = ShellCommandHandler()
+        val shellController =
+            ShellController(
+                context,
+                shellInit,
+                shellCommandHandler,
+                mock<DisplayInsetsController>(),
+                mainExecutor,
+            )
+        val surfaceSynchronizer = { obj: Runnable -> obj.run() }
+
+        val bubbleDataRepository =
+            BubbleDataRepository(
+                mock<LauncherApps>(),
+                mainExecutor,
+                bgExecutor,
+                BubblePersistentRepository(context),
+            )
+
+        val shellTaskOrganizer = mock<ShellTaskOrganizer>()
+        whenever(shellTaskOrganizer.executor).thenReturn(directExecutor())
+
+        return BubbleController(
+            context,
+            shellInit,
+            shellCommandHandler,
+            shellController,
+            bubbleData,
+            surfaceSynchronizer,
+            FloatingContentCoordinator(),
+            bubbleDataRepository,
+            mock<IStatusBarService>(),
+            mock<WindowManager>(),
+            WindowManagerShellWrapper(mainExecutor),
+            mock<UserManager>(),
+            mock<LauncherApps>(),
+            bubbleLogger,
+            mock<TaskStackListenerImpl>(),
+            shellTaskOrganizer,
+            bubblePositioner,
+            mock<DisplayController>(),
+            /* oneHandedOptional= */ Optional.empty(),
+            mock<DragAndDropController>(),
+            mainExecutor,
+            mock<Handler>(),
+            bgExecutor,
+            mock<TaskViewTransitions>(),
+            mock<Transitions>(),
+            SyncTransactionQueue(TransactionPool(), mainExecutor),
+            mock<IWindowManager>(),
+            ProdBubbleProperties,
+        )
+    }
+
+    private class TestExecutor : ShellExecutor {
+
+        private val runnables: MutableList<Runnable> = mutableListOf()
+
+        override fun execute(runnable: Runnable) {
+            runnables.add(runnable)
+        }
+
+        override fun executeDelayed(runnable: Runnable, delayMillis: Long) {
+            execute(runnable)
+        }
+
+        override fun removeCallbacks(runnable: Runnable?) {}
+
+        override fun hasCallback(runnable: Runnable?): Boolean = false
+
+        fun flushAll() {
+            while (runnables.isNotEmpty()) {
+                runnables.removeAt(0).run()
+            }
+        }
+    }
+
+    private class FakeBubblesStateListener : Bubbles.BubbleStateListener {
+        override fun onBubbleStateChange(update: BubbleBarUpdate?) {}
+
+        override fun animateBubbleBarLocation(location: BubbleBarLocation?) {}
+    }
+}
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/FakeBubbleFactory.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/FakeBubbleFactory.kt
index cb6fb62..3279d56 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/FakeBubbleFactory.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/FakeBubbleFactory.kt
@@ -32,10 +32,10 @@
             return BubbleViewInfo().apply { bubbleBarExpandedView = bubbleExpandedView }
         }
 
-        fun createChatBubbleWithViewInfo(
+        fun createChatBubble(
             context: Context,
             key: String = "key",
-            viewInfo: BubbleViewInfo,
+            viewInfo: BubbleViewInfo? = null,
         ): Bubble {
             val bubble =
                 Bubble(
@@ -50,7 +50,9 @@
                     directExecutor(),
                     directExecutor(),
                 ) {}
-            bubble.setViewInfo(viewInfo)
+            if (viewInfo != null) {
+                bubble.setViewInfo(viewInfo)
+            }
             return bubble
         }
     }
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt
index 6ac36a3..1bf6af8 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt
@@ -17,6 +17,7 @@
 package com.android.wm.shell.bubbles.bar
 
 import android.app.ActivityManager
+import android.content.ComponentName
 import android.content.Context
 import android.content.pm.ShortcutInfo
 import android.graphics.Insets
@@ -24,6 +25,7 @@
 import android.view.LayoutInflater
 import android.view.View
 import android.view.WindowManager
+import android.widget.FrameLayout
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -110,9 +112,9 @@
 
         regionSamplingProvider = TestRegionSamplingProvider()
 
-        bubbleExpandedView = (inflater.inflate(
+        bubbleExpandedView = inflater.inflate(
             R.layout.bubble_bar_expanded_view, null, false /* attachToRoot */
-        ) as BubbleBarExpandedView)
+        ) as BubbleBarExpandedView
         bubbleExpandedView.initialize(
             expandedViewManager,
             positioner,
@@ -124,11 +126,11 @@
             regionSamplingProvider,
         )
 
-        getInstrumentation().runOnMainSync(Runnable {
+        getInstrumentation().runOnMainSync {
             bubbleExpandedView.onAttachedToWindow()
             // Helper should be created once attached to window
             testableRegionSamplingHelper = regionSamplingProvider!!.helper
-        })
+        }
 
         bubble = Bubble(
             "key",
@@ -254,6 +256,93 @@
         assertThat(uiEventLoggerFake.logs[0]).hasBubbleInfo(bubble)
     }
 
+    @Test
+    fun animateExpansion_waitsUntilTaskCreated() {
+        var animated = false
+        bubbleExpandedView.animateExpansionWhenTaskViewVisible { animated = true }
+        assertThat(animated).isFalse()
+        bubbleExpandedView.onTaskCreated()
+        assertThat(animated).isTrue()
+    }
+
+    @Test
+    fun animateExpansion_taskViewAttachedAndVisible() {
+        val inflater = LayoutInflater.from(context)
+        val expandedView = inflater.inflate(
+            R.layout.bubble_bar_expanded_view, null, false /* attachToRoot */
+        ) as BubbleBarExpandedView
+        val taskView = FakeBubbleTaskViewFactory().create()
+        val taskViewParent = FrameLayout(context)
+        taskViewParent.addView(taskView.taskView)
+        taskView.listener.onTaskCreated(666, ComponentName(context, "BubbleBarExpandedViewTest"))
+        assertThat(taskView.isVisible).isTrue()
+
+        expandedView.initialize(
+            expandedViewManager,
+            positioner,
+            BubbleLogger(uiEventLoggerFake),
+            false /* isOverflow */,
+            taskView,
+            mainExecutor,
+            bgExecutor,
+            regionSamplingProvider,
+        )
+
+        // the task view should be removed from its parent
+        assertThat(taskView.taskView.parent).isNull()
+
+        var animated = false
+        expandedView.animateExpansionWhenTaskViewVisible { animated = true }
+        assertThat(animated).isFalse()
+
+        // send an invisible signal to simulate the surface getting destroyed
+        expandedView.onContentVisibilityChanged(false)
+
+        // send a visible signal to simulate a new surface getting created
+        expandedView.onContentVisibilityChanged(true)
+
+        assertThat(taskView.taskView.parent).isEqualTo(expandedView)
+        assertThat(animated).isTrue()
+    }
+
+    @Test
+    fun animateExpansion_taskViewAttachedAndInvisible() {
+        val inflater = LayoutInflater.from(context)
+        val expandedView = inflater.inflate(
+            R.layout.bubble_bar_expanded_view, null, false /* attachToRoot */
+        ) as BubbleBarExpandedView
+        val taskView = FakeBubbleTaskViewFactory().create()
+        val taskViewParent = FrameLayout(context)
+        taskViewParent.addView(taskView.taskView)
+        taskView.listener.onTaskCreated(666, ComponentName(context, "BubbleBarExpandedViewTest"))
+        assertThat(taskView.isVisible).isTrue()
+        taskView.listener.onTaskVisibilityChanged(666, false)
+        assertThat(taskView.isVisible).isFalse()
+
+        expandedView.initialize(
+            expandedViewManager,
+            positioner,
+            BubbleLogger(uiEventLoggerFake),
+            false /* isOverflow */,
+            taskView,
+            mainExecutor,
+            bgExecutor,
+            regionSamplingProvider,
+        )
+
+        // the task view should be added to the expanded view
+        assertThat(taskView.taskView.parent).isEqualTo(expandedView)
+
+        var animated = false
+        expandedView.animateExpansionWhenTaskViewVisible { animated = true }
+        assertThat(animated).isFalse()
+
+        // send a visible signal to simulate a new surface getting created
+        expandedView.onContentVisibilityChanged(true)
+
+        assertThat(animated).isTrue()
+    }
+
     private fun BubbleBarExpandedView.menuView(): BubbleBarMenuView {
         return findViewByPredicate { it is BubbleBarMenuView }
     }
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt
index 0044593..7280f8a 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt
@@ -165,7 +165,7 @@
                 }
 
         val viewInfo = FakeBubbleFactory.createViewInfo(bubbleBarExpandedView)
-        bubble = FakeBubbleFactory.createChatBubbleWithViewInfo(context, viewInfo = viewInfo)
+        bubble = FakeBubbleFactory.createChatBubble(context, viewInfo = viewInfo)
     }
 
     @After
@@ -253,6 +253,7 @@
 
         getInstrumentation().runOnMainSync {
             bubbleBarLayerView.showExpandedView(bubble)
+            bubble.bubbleBarExpandedView!!.onContentVisibilityChanged(true)
         }
         waitForExpandedViewAnimation()
 
@@ -276,6 +277,7 @@
 
         getInstrumentation().runOnMainSync {
             bubbleBarLayerView.showExpandedView(bubble)
+            bubble.bubbleBarExpandedView!!.onContentVisibilityChanged(true)
         }
         waitForExpandedViewAnimation()
 
diff --git a/libs/WindowManager/Shell/res/layout/compat_ui_layout.xml b/libs/WindowManager/Shell/res/layout/compat_ui_layout.xml
index e7ead63..62782a7 100644
--- a/libs/WindowManager/Shell/res/layout/compat_ui_layout.xml
+++ b/libs/WindowManager/Shell/res/layout/compat_ui_layout.xml
@@ -22,14 +22,14 @@
     android:gravity="bottom|end">
 
     <include android:id="@+id/size_compat_hint"
-        android:visibility="invisible"
+        android:visibility="gone"
         android:layout_width="@dimen/compat_hint_width"
         android:layout_height="wrap_content"
         layout="@layout/compat_mode_hint"/>
 
     <ImageButton
         android:id="@+id/size_compat_restart_button"
-        android:visibility="invisible"
+        android:visibility="gone"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginEnd="@dimen/compat_button_margin"
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_app_header.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_app_header.xml
index 3dbf754..fcf74e3 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_app_header.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_app_header.xml
@@ -46,15 +46,19 @@
         <TextView
             android:id="@+id/application_name"
             android:layout_width="0dp"
-            android:layout_height="20dp"
-            android:maxWidth="86dp"
+            android:layout_height="wrap_content"
+            android:maxWidth="130dp"
             android:textAppearance="@android:style/TextAppearance.Material.Title"
             android:textSize="14sp"
             android:textFontWeight="500"
-            android:lineHeight="20dp"
+            android:lineHeight="20sp"
             android:layout_gravity="center_vertical"
             android:layout_weight="1"
             android:layout_marginStart="8dp"
+            android:singleLine="true"
+            android:ellipsize="none"
+            android:requiresFadingEdge="horizontal"
+            android:fadingEdgeLength="28dp"
             android:clickable="false"
             android:focusable="false"
             tools:text="Gmail"/>
diff --git a/libs/WindowManager/Shell/res/layout/user_aspect_ratio_settings_layout.xml b/libs/WindowManager/Shell/res/layout/user_aspect_ratio_settings_layout.xml
index b5f04c3..433d854 100644
--- a/libs/WindowManager/Shell/res/layout/user_aspect_ratio_settings_layout.xml
+++ b/libs/WindowManager/Shell/res/layout/user_aspect_ratio_settings_layout.xml
@@ -22,14 +22,14 @@
     android:gravity="bottom|end">
 
     <include android:id="@+id/user_aspect_ratio_settings_hint"
-        android:visibility="invisible"
+        android:visibility="gone"
         android:layout_width="@dimen/compat_hint_width"
         android:layout_height="wrap_content"
         layout="@layout/compat_mode_hint"/>
 
     <ImageButton
         android:id="@+id/user_aspect_ratio_settings_button"
-        android:visibility="invisible"
+        android:visibility="gone"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginEnd="@dimen/compat_button_margin"
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 46ab090..b72d255 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"إغلاق القائمة"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"فتح القائمة"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"تكبير الشاشة إلى أقصى حدّ"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"تغيير الحجم"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"لا يمكن نقل التطبيق إلى هنا"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"مجسَّم"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"استعادة"</string>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index 10a33bb..c2d4d8b 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite meni"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otvorite meni"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Povećaj ekran"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Promeni veličinu"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacija ne može da se premesti ovde"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Imerzivne"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Vrati"</string>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index d7da3ae..7e80484 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Затваряне на менюто"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Отваряне на менюто"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Увеличаване на екрана"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Преоразмеряване"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Приложението не може да бъде преместено тук"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Реалистично"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Възстановяване"</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 4249373..786ed76 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Tanca el menú"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Obre el menú"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximitza la pantalla"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Canvia la mida"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"L\'aplicació no es pot moure aquí"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersiu"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restaura"</string>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index a125343..99e9a83 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Zavřít nabídku"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otevřít nabídku"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximalizovat obrazovku"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Změnit velikost"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikaci sem nelze přesunout"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Pohlcující"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Obnovit"</string>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index 85a44f6..879347ad 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Κλείσιμο μενού"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Άνοιγμα μενού"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Μεγιστοποίηση οθόνης"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Αλλαγή μεγέθους"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Δεν είναι δυνατή η μετακίνηση της εφαρμογής εδώ"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Καθηλωτικό"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Επαναφορά"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index 3e30ff0..358e314 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Open menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersive"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restore"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index 0d7189b..923f30b 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Close Menu"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Open Menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximize Screen"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersive"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restore"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index 3e30ff0..358e314 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Open menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersive"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restore"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index 3e30ff0..358e314 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Open menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersive"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restore"</string>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index 6a1a2e5..7a2e8cf 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir el menú"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Cambiar el tamaño"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"No se puede mover la app aquí"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Inmersivo"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restablecer"</string>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index f0d1d4e..9a15f90 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Sule menüü"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Ava menüü"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Kuva täisekraanil"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Suuruse muutmine"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Rakendust ei saa siia teisaldada"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Kaasahaarav"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Taasta"</string>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index d10a02d..eb50ba7 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"بستن منو"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"باز کردن منو"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"بزرگ کردن صفحه"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"تغییر اندازه"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"برنامه را نمی‌توان به اینجا منتقل کرد"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"فراگیر"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"بازیابی"</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index 0eab10c..696650a 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"मेन्यू बंद करें"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"मेन्यू खोलें"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रीन को बड़ा करें"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"साइज़ बदलें"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ऐप्लिकेशन को यहां मूव नहीं किया जा सकता"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"इमर्सिव"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"वापस लाएं"</string>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 59a95f0..72669424 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Փակել ընտրացանկը"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Բացել ընտրացանկը"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ծավալել էկրանը"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Փոխել չափը"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Հավելվածը հնարավոր չէ տեղափոխել այստեղ"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Ներկայության էֆեկտով"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Վերականգնել"</string>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index b75c041..8ea5c44 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -79,7 +79,7 @@
     <string name="bubbles_user_education_description" msgid="4215862563054175407">"Le nuove conversazioni vengono mostrate come icone mobili o bolle. Tocca per aprire la bolla. Trascinala per spostarla."</string>
     <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Controlla le bolle quando vuoi"</string>
     <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Tocca Gestisci per disattivare le bolle dall\'app"</string>
-    <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
+    <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Ok"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nessuna bolla recente"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Le bolle recenti e ignorate appariranno qui"</string>
     <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Chatta utilizzando le bolle"</string>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index 2960a19..8cc7372 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"メニューを閉じる"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"メニューを開く"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"画面の最大化"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"サイズ変更"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"アプリはここに移動できません"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"没入モード"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"復元"</string>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index 9710e69..fab0cb2 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"ປິດເມນູ"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"ເປີດເມນູ"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ປັບຈໍໃຫຍ່ສຸດ"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ປັບຂະໜາດ"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ບໍ່ສາມາດຍ້າຍແອັບມາບ່ອນນີ້ໄດ້"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ສົມຈິງ"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ກູ້ຄືນ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index 7e20ee1..c2e747c 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"മെനു അടയ്ക്കുക"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"മെനു തുറക്കുക"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"സ്‌ക്രീൻ വലുതാക്കുക"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"വലുപ്പം മാറ്റുക"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ആപ്പ് ഇവിടേക്ക് നീക്കാനാകില്ല"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ഇമേഴ്‌സീവ്"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"പുനഃസ്ഥാപിക്കുക"</string>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index b28b690..886ef79 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Menu sluiten"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menu openen"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Scherm maximaliseren"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Formaat aanpassen"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Kan de app niet hierheen verplaatsen"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersief"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Herstellen"</string>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index e82916b..fa0e7c3 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Zamknij menu"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otwórz menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksymalizuj ekran"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Zmień rozmiar"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Nie można przenieść aplikacji tutaj"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Tryb immersyjny"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Przywróć"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index e0e91e7..28dc7b0 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar ecrã"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Redimensionar"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Não é possível mover a app para aqui"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Envolvente"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restaurar"</string>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index 063e47c..55452bd 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Zapri meni"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Odpri meni"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimiraj zaslon"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Spremeni velikost"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacije ni mogoče premakniti sem"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Poglobljeno"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Obnovi"</string>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index f74e460..af8ac68 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Затворите мени"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Отворите мени"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Повећај екран"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Промени величину"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Апликација не може да се премести овде"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Имерзивне"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Врати"</string>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 7a5549e..0c3c18c 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Stäng menyn"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Öppna menyn"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximera skärmen"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Ändra storlek"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Det går inte att flytta appen hit"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Uppslukande"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Återställ"</string>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index fe75561..7be7373 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"ปิดเมนู"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"เปิดเมนู"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ขยายหน้าจอให้ใหญ่สุด"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ปรับขนาด"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ย้ายแอปมาที่นี่ไม่ได้"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"สมจริง"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"คืนค่า"</string>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index d9fb13b..22b0174 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Isara ang Menu"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Buksan ang Menu"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"I-maximize ang Screen"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"I-resize"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Hindi mailipat dito ang app"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersive"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"I-restore"</string>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 3417fef..c64b843 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -133,8 +133,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Menyuni yopish"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menyuni ochish"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranni yoyish"</string>
-    <!-- no translation found for desktop_mode_maximize_menu_snap_text (5673738963174074006) -->
-    <skip />
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Oʻlchamini oʻzgartirish"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ilova bu yerga surilmaydi"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersiv"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Tiklash"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index e1ecd44..f3202a1 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -125,7 +125,7 @@
     <string name="select_text" msgid="5139083974039906583">"選取"</string>
     <string name="screenshot_text" msgid="1477704010087786671">"螢幕截圖"</string>
     <string name="open_in_browser_text" msgid="9181692926376072904">"在瀏覽器中開啟"</string>
-    <string name="open_in_app_text" msgid="2874590745116268525">"在應用程式中開啟"</string>
+    <string name="open_in_app_text" msgid="2874590745116268525">"喺應用程式入面打開"</string>
     <string name="new_window_text" msgid="6318648868380652280">"新視窗"</string>
     <string name="manage_windows_text" msgid="5567366688493093920">"管理視窗"</string>
     <string name="change_aspect_ratio_text" msgid="9104456064548212806">"變更長寬比"</string>
diff --git a/libs/WindowManager/Shell/shared/res/values/strings.xml b/libs/WindowManager/Shell/shared/res/values/strings.xml
new file mode 100644
index 0000000..d1804c0
--- /dev/null
+++ b/libs/WindowManager/Shell/shared/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    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.
+-->
+<resources>
+  <!-- Accessibility text for the icons generated by the Manage Windows submenu
+  in desktop mode and taskbar. [CHAR LIMIT=NONE] -->
+  <string name="manage_windows_icon_text">Open Window %1$d</string>
+</resources>
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/multiinstance/ManageWindowsViewContainer.kt
similarity index 95%
rename from libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt
rename to libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/multiinstance/ManageWindowsViewContainer.kt
index f14dfdb..0954b52 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/multiinstance/ManageWindowsViewContainer.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.wm.shell.shared.desktopmode
+package com.android.wm.shell.shared.multiinstance
 import android.animation.Animator
 import android.animation.AnimatorListenerAdapter
 import android.animation.AnimatorSet
@@ -34,6 +34,7 @@
 import android.view.ViewGroup.MarginLayoutParams
 import android.widget.LinearLayout
 import android.window.TaskSnapshot
+import com.android.wm.shell.shared.R
 
 /**
  * View for the All Windows menu option, used by both Desktop Windowing and Taskbar.
@@ -167,6 +168,9 @@
                 val appSnapshotButton = SurfaceView(context)
                 appSnapshotButton.cornerRadius = iconRadius
                 appSnapshotButton.setZOrderOnTop(true)
+                appSnapshotButton.contentDescription = context.resources.getString(
+                    R.string.manage_windows_icon_text, iconCount + 1
+                )
                 appSnapshotButton.setOnClickListener {
                     onIconClickListener?.invoke(taskId)
                 }
@@ -230,10 +234,12 @@
         /** Play the animation for opening the menu. */
         fun animateOpen() {
             animateView(rootView, MENU_BOUNDS_SHRUNK_SCALE, MENU_BOUNDS_FULL_SCALE,
-                MENU_START_ALPHA, MENU_FULL_ALPHA)
+                MENU_START_ALPHA, MENU_FULL_ALPHA
+            )
             for (view in iconViews) {
                 animateView(view, MENU_BOUNDS_SHRUNK_SCALE, MENU_BOUNDS_FULL_SCALE,
-                    MENU_START_ALPHA, MENU_FULL_ALPHA)
+                    MENU_START_ALPHA, MENU_FULL_ALPHA
+                )
             }
             createAnimatorSet().start()
         }
@@ -241,10 +247,12 @@
         /** Play the animation for closing the menu. */
         fun animateClose(callback: () -> Unit) {
             animateView(rootView, MENU_BOUNDS_FULL_SCALE, MENU_BOUNDS_SHRUNK_SCALE,
-                MENU_FULL_ALPHA, MENU_START_ALPHA)
+                MENU_FULL_ALPHA, MENU_START_ALPHA
+            )
             for (view in iconViews) {
                 animateView(view, MENU_BOUNDS_FULL_SCALE, MENU_BOUNDS_SHRUNK_SCALE,
-                    MENU_FULL_ALPHA, MENU_START_ALPHA)
+                    MENU_FULL_ALPHA, MENU_START_ALPHA
+                )
             }
             createAnimatorSet().apply {
                 addListener(
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 ce7a977..e9cfd9b 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
@@ -37,6 +37,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
+import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.IActivityTaskManager;
 import android.app.TaskInfo;
@@ -73,10 +74,12 @@
 import android.window.BackNavigationInfo;
 import android.window.BackTouchTracker;
 import android.window.IBackAnimationFinishedCallback;
+import android.window.IBackAnimationHandoffHandler;
 import android.window.IBackAnimationRunner;
 import android.window.IOnBackInvokedCallback;
 import android.window.TransitionInfo;
 import android.window.TransitionRequestInfo;
+import android.window.WindowAnimationState;
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
@@ -84,6 +87,8 @@
 import com.android.internal.protolog.ProtoLog;
 import com.android.internal.util.LatencyTracker;
 import com.android.internal.view.AppearanceRegion;
+import com.android.systemui.animation.TransitionAnimator;
+import com.android.window.flags.Flags;
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.ExternalInterfaceBinder;
 import com.android.wm.shell.common.RemoteCallable;
@@ -227,6 +232,15 @@
     private Runnable mPilferPointerCallback;
     private BackAnimation.TopUiRequest mRequestTopUiCallback;
 
+    private final IBackAnimationHandoffHandler mHandoffHandler =
+            new IBackAnimationHandoffHandler.Stub() {
+                @Override
+                public void handOffAnimation(
+                        RemoteAnimationTarget[] targets, WindowAnimationState[] states) {
+                    mBackTransitionHandler.handOffAnimation(targets, states);
+                }
+            };
+
     public BackAnimationController(
             @NonNull ShellInit shellInit,
             @NonNull ShellController shellController,
@@ -282,7 +296,7 @@
         mShellCommandHandler = shellCommandHandler;
         mWindowManager = context.getSystemService(WindowManager.class);
         mTransitions = transitions;
-        mBackTransitionHandler = new BackTransitionHandler();
+        mBackTransitionHandler = new BackTransitionHandler(mTransitions);
         mTransitions.addHandler(mBackTransitionHandler);
         mHandler = handler;
         mTransitions.registerObserver(mBackTransitionObserver);
@@ -715,6 +729,9 @@
         }
         try {
             callback.onBackStarted(backEvent);
+            if (mBackTransitionHandler.canHandOffAnimation()) {
+                callback.setHandoffHandler(mHandoffHandler);
+            }
             mOnBackStartDispatched = true;
         } catch (RemoteException e) {
             Log.e(TAG, "dispatchOnBackStarted error: ", e);
@@ -1192,6 +1209,7 @@
     }
 
     class BackTransitionHandler implements Transitions.TransitionHandler {
+        private final Transitions mTransitions;
 
         Runnable mOnAnimationFinishCallback;
         boolean mCloseTransitionRequested;
@@ -1203,6 +1221,12 @@
         // animation is canceled, start a close prepare transition to finish the whole transition.
         IBinder mClosePrepareTransition;
         TransitionInfo mOpenTransitionInfo;
+        Transitions.TransitionHandler mTakeoverHandler;
+
+        BackTransitionHandler(Transitions transitions) {
+            mTransitions = transitions;
+        }
+
         void onAnimationFinished() {
             if (!mCloseTransitionRequested && mPrepareOpenTransition != null) {
                 createClosePrepareTransition();
@@ -1214,18 +1238,23 @@
         }
 
         private void applyFinishOpenTransition() {
-            mOpenTransitionInfo = null;
-            mPrepareOpenTransition = null;
             if (mFinishOpenTransaction != null) {
                 final SurfaceControl.Transaction t = mFinishOpenTransaction;
-                mFinishOpenTransaction = null;
                 t.apply();
             }
             if (mFinishOpenTransitionCallback != null) {
                 final Transitions.TransitionFinishCallback callback = mFinishOpenTransitionCallback;
-                mFinishOpenTransitionCallback = null;
                 callback.onTransitionFinished(null);
             }
+            cleanUpInternalState();
+        }
+
+        private void cleanUpInternalState() {
+            mOpenTransitionInfo = null;
+            mPrepareOpenTransition = null;
+            mFinishOpenTransaction = null;
+            mFinishOpenTransitionCallback = null;
+            mTakeoverHandler = null;
         }
 
         private void applyAndFinish(@NonNull SurfaceControl.Transaction st,
@@ -1237,6 +1266,7 @@
             finishCallback.onTransitionFinished(null);
             mCloseTransitionRequested = false;
         }
+
         @Override
         public boolean startAnimation(@NonNull IBinder transition,
                 @NonNull TransitionInfo info,
@@ -1246,6 +1276,9 @@
             final boolean isPrepareTransition =
                     info.getType() == WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION;
             if (isPrepareTransition) {
+                if (checkTakeoverFlags()) {
+                    mTakeoverHandler = mTransitions.getHandlerForTakeover(transition, info);
+                }
                 kickStartAnimation();
             }
             // Both mShellExecutor and Transitions#mMainExecutor are ShellMainThread, so we don't
@@ -1288,6 +1321,57 @@
             return handleCloseTransition(info, st, ft, finishCallback);
         }
 
+        private boolean canHandOffAnimation() {
+            if (!checkTakeoverFlags()) {
+                return false;
+            }
+
+            return mTakeoverHandler != null;
+        }
+
+        private void handOffAnimation(
+                RemoteAnimationTarget[] targets, WindowAnimationState[] states) {
+            if (!checkTakeoverFlags()) {
+                ProtoLog.e(WM_SHELL_BACK_PREVIEW,
+                        "Trying to hand off the animation, but the required flags are disabled.");
+                return;
+            } else if (mTakeoverHandler == null) {
+                ProtoLog.e(WM_SHELL_BACK_PREVIEW,
+                        "Missing takeover handler when trying to hand off animation.");
+                return;
+            } else if (targets.length != states.length) {
+                ProtoLog.e(WM_SHELL_BACK_PREVIEW,
+                        "Targets passed for takeover don't match the window states.");
+                return;
+            }
+
+            // The states passed to this method are paired with the targets, but they need to be
+            // paired with the changes inside the TransitionInfo. So for each change we find its
+            // matching target, and leave the state for any change missing a matching target blank.
+            WindowAnimationState[] updatedStates =
+                    new WindowAnimationState[mOpenTransitionInfo.getChanges().size()];
+            for (int i = 0; i < mOpenTransitionInfo.getChanges().size(); i++) {
+                ActivityManager.RunningTaskInfo taskInfo =
+                        mOpenTransitionInfo.getChanges().get(i).getTaskInfo();
+                if (taskInfo == null) {
+                    continue;
+                }
+
+                for (int j = 0; j < targets.length; j++) {
+                    if (taskInfo.taskId == targets[j].taskId) {
+                        updatedStates[i] = states[j];
+                        break;
+                    }
+                }
+            }
+
+            mTakeoverHandler.takeOverAnimation(
+                    mPrepareOpenTransition, mOpenTransitionInfo, new SurfaceControl.Transaction(),
+                    mFinishOpenTransitionCallback, updatedStates);
+
+            cleanUpInternalState();
+        }
+
         @Override
         public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted,
                 @Nullable SurfaceControl.Transaction finishTransaction) {
@@ -1673,6 +1757,11 @@
             }
             return null;
         }
+
+        private static boolean checkTakeoverFlags() {
+            return TransitionAnimator.Companion.longLivedReturnAnimationsEnabled()
+                    && Flags.unifyBackNavigationTransition();
+        }
     }
 
     private static boolean isNotGestureBackTransition(@NonNull TransitionInfo info) {
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 3733930..7e5a82e 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
@@ -39,6 +39,8 @@
 import android.view.animation.Interpolator
 import android.view.animation.Transformation
 import android.window.BackEvent
+import android.window.BackEvent.EDGE_LEFT
+import android.window.BackEvent.EDGE_RIGHT
 import android.window.BackMotionEvent
 import android.window.BackNavigationInfo
 import android.window.BackProgressAnimator
@@ -50,6 +52,7 @@
 import com.android.internal.policy.ScreenDecorationsUtils
 import com.android.internal.policy.SystemBarUtils
 import com.android.internal.protolog.ProtoLog
+import com.android.window.flags.Flags.predictiveBackTimestampApi
 import com.android.wm.shell.R
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer
 import com.android.wm.shell.protolog.ShellProtoLogGroup
@@ -118,7 +121,9 @@
     private val postCommitFlingSpring = SpringForce(SPRING_SCALE)
             .setStiffness(SpringForce.STIFFNESS_LOW)
             .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
+    private var swipeEdge = EDGE_LEFT
     protected var gestureProgress = 0f
+    private val velocityTracker = ProgressVelocityTracker()
 
     /** Background color to be used during the animation, also see [getBackgroundColor] */
     protected var customizedBackgroundColor = 0
@@ -175,6 +180,7 @@
             )
             return
         }
+        swipeEdge = backMotionEvent.swipeEdge
         triggerBack = backMotionEvent.triggerBack
         initialTouchPos.set(backMotionEvent.touchX, backMotionEvent.touchY)
 
@@ -241,6 +247,9 @@
         )
         applyTransaction()
         background.customizeStatusBarAppearance(currentClosingRect.top.toInt())
+        if (predictiveBackTimestampApi()) {
+            velocityTracker.addPosition(backEvent.frameTimeMillis, progress)
+        }
     }
 
     private fun getYOffset(centeredRect: RectF, touchY: Float): Float {
@@ -272,10 +281,19 @@
 
         // kick off spring animation with the current velocity from the pre-commit phase, this
         // affects the scaling of the closing and/or opening activity during post-commit
-        val startVelocity =
-            if (gestureProgress < 0.1f) -DEFAULT_FLING_VELOCITY else -velocity * SPRING_SCALE
+
+        var startVelocity = if (predictiveBackTimestampApi()) {
+            // pronounce fling animation more for gestures
+            val velocityFactor = if (swipeEdge == EDGE_LEFT || swipeEdge == EDGE_RIGHT) 2f else 1f
+            velocity * SPRING_SCALE * (1f - MAX_SCALE) * velocityFactor
+        } else {
+            velocity * SPRING_SCALE
+        }
+        if (gestureProgress < 0.1f) {
+            startVelocity = startVelocity.coerceAtLeast(DEFAULT_FLING_VELOCITY)
+        }
         val flingAnimation = SpringAnimation(postCommitFlingScale, SPRING_SCALE)
-            .setStartVelocity(startVelocity.coerceIn(-MAX_FLING_VELOCITY, 0f))
+            .setStartVelocity(-startVelocity.coerceIn(0f, MAX_FLING_VELOCITY))
             .setStartValue(SPRING_SCALE)
             .setSpring(postCommitFlingSpring)
         flingAnimation.start()
@@ -338,6 +356,7 @@
         lastPostCommitFlingScale = SPRING_SCALE
         gestureProgress = 0f
         triggerBack = false
+        velocityTracker.resetTracking()
     }
 
     protected fun applyTransform(
@@ -520,7 +539,11 @@
         override fun onBackInvoked() {
             triggerBack = true
             progressAnimator.reset()
-            onGestureCommitted(progressAnimator.velocity)
+            if (predictiveBackTimestampApi()) {
+                onGestureCommitted(velocityTracker.calculateVelocity())
+            } else {
+                onGestureCommitted(progressAnimator.velocity)
+            }
         }
     }
 
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 dc50fdb..f48b3ff 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
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.back;
 
-import static android.view.MotionEvent.ACTION_MOVE;
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
 import static android.window.BackEvent.EDGE_RIGHT;
@@ -43,10 +42,8 @@
 import android.view.Choreographer;
 import android.view.IRemoteAnimationFinishedCallback;
 import android.view.IRemoteAnimationRunner;
-import android.view.MotionEvent;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
-import android.view.VelocityTracker;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.window.BackEvent;
@@ -132,9 +129,8 @@
     private final SpringForce mPostCommitFlingSpring = new SpringForce(SPRING_SCALE)
             .setStiffness(FLING_SPRING_STIFFNESS)
             .setDampingRatio(1f);
-    private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
+    private final ProgressVelocityTracker mVelocityTracker = new ProgressVelocityTracker();
     private float mGestureProgress = 0f;
-    private long mDownTime = 0L;
 
     @Inject
     public CrossTaskBackAnimation(Context context, BackAnimationBackground background,
@@ -316,8 +312,7 @@
         mClosingCurrentRect.setEmpty();
         mInitialTouchPos.set(0, 0);
         mGestureProgress = 0;
-        mDownTime = 0;
-        mVelocityTracker.clear();
+        mVelocityTracker.resetTracking();
 
         if (mFinishCallback != null) {
             try {
@@ -333,22 +328,13 @@
     private void onGestureProgress(@NonNull BackEvent backEvent) {
         if (!mBackInProgress) {
             mBackInProgress = true;
-            mDownTime = backEvent.getFrameTimeMillis();
         }
         float progress = backEvent.getProgress();
         mTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY());
         float interpolatedProgress = getInterpolatedProgress(progress);
         if (predictiveBackTimestampApi()) {
-            mVelocityTracker.addMovement(
-                    MotionEvent.obtain(
-                            /* downTime */ mDownTime,
-                            /* eventTime */ backEvent.getFrameTimeMillis(),
-                            /* action */ ACTION_MOVE,
-                            /* x */ interpolatedProgress * SPRING_SCALE,
-                            /* y */ 0f,
-                            /* metaState */ 0
-                    )
-            );
+            mVelocityTracker.addPosition(backEvent.getFrameTimeMillis(),
+                    interpolatedProgress * SPRING_SCALE);
         }
         updateGestureBackProgress(interpolatedProgress, backEvent);
     }
@@ -362,9 +348,8 @@
         if (predictiveBackTimestampApi()) {
             // kick off spring animation with the current velocity from the pre-commit phase, this
             // affects the scaling of the closing and/or opening task during post-commit
-            mVelocityTracker.computeCurrentVelocity(1000);
             float startVelocity = mGestureProgress < 0.1f
-                    ? -DEFAULT_FLING_VELOCITY : -mVelocityTracker.getXVelocity();
+                    ? -DEFAULT_FLING_VELOCITY : -mVelocityTracker.calculateVelocity();
             SpringAnimation flingAnimation =
                     new SpringAnimation(mPostCommitFlingScale, SPRING_SCALE)
                     .setStartVelocity(Math.max(-MAX_FLING_VELOCITY, Math.min(0f, startVelocity)))
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/ProgressVelocityTracker.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/ProgressVelocityTracker.kt
new file mode 100644
index 0000000..6bbda0f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/ProgressVelocityTracker.kt
@@ -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.wm.shell.back
+
+import android.view.MotionEvent
+import android.view.VelocityTracker
+
+internal class ProgressVelocityTracker {
+    private val velocityTracker: VelocityTracker = VelocityTracker.obtain()
+    private var downTime = -1L
+
+    fun addPosition(timeMillis: Long, position: Float) {
+        if (downTime == -1L) downTime = timeMillis
+        velocityTracker.addMovement(
+            MotionEvent.obtain(
+                /* downTime */ downTime,
+                /* eventTime */ timeMillis,
+                /* action */ MotionEvent.ACTION_MOVE,
+                /* x */ position,
+                /* y */ 0f,
+                /* metaState */0
+            )
+        )
+    }
+
+    /** calculates current velocity (unit: progress per second) */
+    fun calculateVelocity(): Float {
+        velocityTracker.computeCurrentVelocity(1000)
+        return velocityTracker.xVelocity
+    }
+
+    fun resetTracking() {
+        velocityTracker.clear()
+        downTime = -1L
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index b82496e..3b53c3f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -274,8 +274,11 @@
     private final DragAndDropController mDragAndDropController;
     /** Used to send bubble events to launcher. */
     private Bubbles.BubbleStateListener mBubbleStateListener;
-    /** Used to track previous navigation mode to detect switch to buttons navigation. */
-    private boolean mIsPrevNavModeGestures;
+    /**
+     * Used to track previous navigation mode to detect switch to buttons navigation. Set to
+     * true to switch the bubble bar to the opposite side for 3 nav buttons mode on device boot.
+     */
+    private boolean mIsPrevNavModeGestures = true;
     /** Used to send updates to the views from {@link #mBubbleDataListener}. */
     private BubbleViewCallback mBubbleViewCallback;
 
@@ -357,7 +360,6 @@
             }
         };
         mExpandedViewManager = BubbleExpandedViewManager.fromBubbleController(this);
-        mIsPrevNavModeGestures = ContextUtils.isGestureNavigationMode(mContext);
     }
 
     private void registerOneHandedState(OneHandedController oneHanded) {
@@ -593,9 +595,9 @@
         if (mBubbleStateListener != null) {
             boolean isCurrentNavModeGestures = ContextUtils.isGestureNavigationMode(mContext);
             if (mIsPrevNavModeGestures && !isCurrentNavModeGestures) {
-                BubbleBarLocation navButtonsLocation = ContextUtils.isRtl(mContext)
+                BubbleBarLocation bubbleBarLocation = ContextUtils.isRtl(mContext)
                         ? BubbleBarLocation.RIGHT : BubbleBarLocation.LEFT;
-                mBubblePositioner.setBubbleBarLocation(navButtonsLocation);
+                mBubblePositioner.setBubbleBarLocation(bubbleBarLocation);
             }
             mIsPrevNavModeGestures = isCurrentNavModeGestures;
             BubbleBarUpdate update = mBubbleData.getInitialStateForBubbleBar();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index 2945691..dc2025b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -898,7 +898,10 @@
             Bubble oldest = mOverflowBubbles.get(mOverflowBubbles.size() - 1);
             ProtoLog.d(WM_SHELL_BUBBLES, "overflow full, remove=%s", oldest.getKey());
             mStateChange.bubbleRemoved(oldest, Bubbles.DISMISS_OVERFLOW_MAX_REACHED);
-            mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_MAX_REACHED);
+            if (!mPositioner.isShowingInBubbleBar()) {
+                // Only logged for bubbles in stack view
+                mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_MAX_REACHED);
+            }
             mOverflowBubbles.remove(oldest);
             mStateChange.removedOverflowBubble = oldest;
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 068b2d2..0fd4206 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -101,9 +101,13 @@
     private int mBubbleBarTopOnScreen;
 
     public BubblePositioner(Context context, WindowManager windowManager) {
+        this(context, DeviceConfig.create(context, windowManager));
+    }
+
+    public BubblePositioner(Context context, DeviceConfig deviceConfig) {
         mContext = context;
-        mDeviceConfig = DeviceConfig.create(context, windowManager);
-        update(mDeviceConfig);
+        mDeviceConfig = deviceConfig;
+        update(deviceConfig);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskView.kt
index 68fc0c9..a517a2d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskView.kt
@@ -42,6 +42,16 @@
     var componentName: ComponentName? = null
       private set
 
+    /**
+     * Whether the task view is visible and has a surface. Note that this does not check the alpha
+     * value of the task view.
+     *
+     * When this is `true` it is safe to start showing the task view. Otherwise if this is `false`
+     * callers should wait for it to be visible which will be indicated either by a call to
+     * [TaskView.Listener.onTaskCreated] or [TaskView.Listener.onTaskVisibilityChanged]. */
+    var isVisible = false
+      private set
+
     /** [TaskView.Listener] for users of this class. */
     var delegateListener: TaskView.Listener? = null
 
@@ -61,9 +71,12 @@
             this@BubbleTaskView.taskId = taskId
             isCreated = true
             componentName = name
+            // when the task is created it is visible
+            isVisible = true
         }
 
         override fun onTaskVisibilityChanged(taskId: Int, visible: Boolean) {
+            this@BubbleTaskView.isVisible = visible
             delegateListener?.onTaskVisibilityChanged(taskId, visible)
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index 74c3748..a313bd0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -161,6 +161,7 @@
 
         updateExpandedView();
         bbev.setAnimating(true);
+        bbev.setSurfaceZOrderedOnTop(true);
         bbev.setContentVisibility(false);
         bbev.setAlpha(0f);
         bbev.setTaskViewAlpha(0f);
@@ -171,28 +172,29 @@
 
         bbev.setAnimationMatrix(mExpandedViewContainerMatrix);
 
-        mExpandedViewAlphaAnimator.start();
+        bbev.animateExpansionWhenTaskViewVisible(() -> {
+            mExpandedViewAlphaAnimator.start();
 
-        PhysicsAnimator.getInstance(mExpandedViewContainerMatrix).cancel();
-        PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
-                .spring(AnimatableScaleMatrix.SCALE_X,
-                        AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
-                        mScaleInSpringConfig)
-                .spring(AnimatableScaleMatrix.SCALE_Y,
-                        AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
-                        mScaleInSpringConfig)
-                .addUpdateListener((target, values) -> {
-                    bbev.setAnimationMatrix(mExpandedViewContainerMatrix);
-                })
-                .withEndActions(() -> {
-                    bbev.setAnimationMatrix(null);
-                    updateExpandedView();
-                    bbev.setSurfaceZOrderedOnTop(false);
-                    if (afterAnimation != null) {
-                        afterAnimation.run();
-                    }
-                })
-                .start();
+            PhysicsAnimator.getInstance(mExpandedViewContainerMatrix).cancel();
+            PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
+                    .spring(AnimatableScaleMatrix.SCALE_X,
+                            AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
+                            mScaleInSpringConfig)
+                    .spring(AnimatableScaleMatrix.SCALE_Y,
+                            AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
+                            mScaleInSpringConfig)
+                    .addUpdateListener((target, values) -> {
+                        bbev.setAnimationMatrix(mExpandedViewContainerMatrix);
+                    })
+                    .withEndActions(() -> {
+                        bbev.setAnimationMatrix(null);
+                        updateExpandedView();
+                        if (afterAnimation != null) {
+                            afterAnimation.run();
+                        }
+                    })
+                    .start();
+        });
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index 3764bcd..ed49417 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -131,6 +131,11 @@
     /** Current corner radius */
     private float mCurrentCornerRadius = 0f;
 
+    /** A runnable to start the expansion animation as soon as the task view is made visible. */
+    @Nullable
+    private Runnable mAnimateExpansion = null;
+    private TaskViewVisibilityState mVisibilityState = TaskViewVisibilityState.INVISIBLE;
+
     /**
      * Whether we want the {@code TaskView}'s content to be visible (alpha = 1f). If
      * {@link #mIsAnimating} is true, this may not reflect the {@code TaskView}'s actual alpha
@@ -140,6 +145,18 @@
     private boolean mIsAnimating;
     private boolean mIsDragging;
 
+    /** An enum value that tracks the visibility state of the task view */
+    private enum TaskViewVisibilityState {
+        /** The task view is going away, and we're waiting for the surface to be destroyed. */
+        PENDING_INVISIBLE,
+        /** The task view is invisible and does not have a surface. */
+        INVISIBLE,
+        /** The task view is in the process of being added to a surface. */
+        PENDING_VISIBLE,
+        /** The task view is visible and has a surface. */
+        VISIBLE
+    }
+
     public BubbleBarExpandedView(Context context) {
         this(context, null);
     }
@@ -206,16 +223,27 @@
             mBubbleTaskViewHelper = new BubbleTaskViewHelper(mContext, expandedViewManager,
                     /* listener= */ this, bubbleTaskView,
                     /* viewParent= */ this);
+
+            // if the task view is already attached to a parent we need to remove it
             if (mTaskView.getParent() != null) {
+                // it's possible that the task view is visible, e.g. if we're unfolding, in which
+                // case removing it will trigger a visibility change. we have to wait for that
+                // signal before we can add it to this expanded view, otherwise the signal will be
+                // incorrect because the task view will have a surface.
+                // if the task view is not visible, then it has no surface and removing it will not
+                // trigger any visibility change signals.
+                if (bubbleTaskView.isVisible()) {
+                    mVisibilityState = TaskViewVisibilityState.PENDING_INVISIBLE;
+                }
                 ((ViewGroup) mTaskView.getParent()).removeView(mTaskView);
             }
-            FrameLayout.LayoutParams lp =
-                    new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);
-            addView(mTaskView, lp);
-            mTaskView.setEnableSurfaceClipping(true);
-            mTaskView.setCornerRadius(mCurrentCornerRadius);
-            mTaskView.setVisibility(VISIBLE);
-            mTaskView.setCaptionInsets(Insets.of(0, mCaptionHeight, 0, 0));
+
+            // if we're invisible it's safe to setup the task view and then await on the visibility
+            // signal.
+            if (mVisibilityState == TaskViewVisibilityState.INVISIBLE) {
+                mVisibilityState = TaskViewVisibilityState.PENDING_VISIBLE;
+                setupTaskView();
+            }
 
             // Handle view needs to draw on top of task view.
             bringChildToFront(mHandleView);
@@ -269,6 +297,16 @@
         });
     }
 
+    private void setupTaskView() {
+        FrameLayout.LayoutParams lp =
+                new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);
+        addView(mTaskView, lp);
+        mTaskView.setEnableSurfaceClipping(true);
+        mTaskView.setCornerRadius(mCurrentCornerRadius);
+        mTaskView.setVisibility(VISIBLE);
+        mTaskView.setCaptionInsets(Insets.of(0, mCaptionHeight, 0, 0));
+    }
+
     public BubbleBarHandleView getHandleView() {
         return mHandleView;
     }
@@ -326,15 +364,28 @@
 
     @Override
     public void onTaskCreated() {
-        setContentVisibility(true);
+        if (mTaskView != null) {
+            mTaskView.setAlpha(0);
+        }
         if (mListener != null) {
             mListener.onTaskCreated();
         }
+        // when the task is created we're visible
+        onTaskViewVisible();
     }
 
     @Override
     public void onContentVisibilityChanged(boolean visible) {
-        setContentVisibility(visible);
+        if (mVisibilityState == TaskViewVisibilityState.PENDING_INVISIBLE && !visible) {
+            // the surface is now destroyed. set up the task view and wait for the visibility
+            // signal.
+            mVisibilityState = TaskViewVisibilityState.PENDING_VISIBLE;
+            setupTaskView();
+            return;
+        }
+        if (visible) {
+            onTaskViewVisible();
+        }
     }
 
     @Override
@@ -350,6 +401,25 @@
         mListener.onBackPressed();
     }
 
+    void animateExpansionWhenTaskViewVisible(Runnable animateExpansion) {
+        if (mVisibilityState == TaskViewVisibilityState.VISIBLE || mIsOverflow) {
+            animateExpansion.run();
+        } else {
+            mAnimateExpansion = animateExpansion;
+        }
+    }
+
+    private void onTaskViewVisible() {
+        // if we're waiting to be visible, start the expansion animation if it's pending.
+        if (mVisibilityState == TaskViewVisibilityState.PENDING_VISIBLE) {
+            mVisibilityState = TaskViewVisibilityState.VISIBLE;
+            if (mAnimateExpansion != null) {
+                mAnimateExpansion.run();
+                mAnimateExpansion = null;
+            }
+        }
+    }
+
     /**
      * Set whether this view is currently being dragged.
      *
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index 38087c0..38b8592 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -403,8 +403,11 @@
 
         @Override
         // TODO(b/335404678): pass control target
-        public void setImeInputTargetRequestedVisibility(boolean visible) {
+        public void setImeInputTargetRequestedVisibility(boolean visible,
+                @NonNull ImeTracker.Token statsToken) {
             if (android.view.inputmethod.Flags.refactorInsetsController()) {
+                ImeTracker.forLogging().onProgress(statsToken,
+                        ImeTracker.PHASE_WM_DISPLAY_IME_CONTROLLER_SET_IME_REQUESTED_VISIBLE);
                 mImeRequestedVisible = visible;
                 dispatchImeRequested(mDisplayId, mImeRequestedVisible);
 
@@ -414,21 +417,21 @@
                 // therefore have to start the show animation from here
                 startAnimation(mImeRequestedVisible /* show */, false /* forceRestart */);
 
-                setVisibleDirectly(mImeRequestedVisible || mAnimation != null);
+                setVisibleDirectly(mImeRequestedVisible || mAnimation != null, statsToken);
             }
         }
 
         /**
          * Sends the local visibility state back to window manager. Needed for legacy adjustForIme.
          */
-        private void setVisibleDirectly(boolean visible) {
+        private void setVisibleDirectly(boolean visible, @Nullable ImeTracker.Token statsToken) {
             mInsetsState.setSourceVisible(InsetsSource.ID_IME, visible);
             mRequestedVisibleTypes = visible
                     ? mRequestedVisibleTypes | WindowInsets.Type.ime()
                     : mRequestedVisibleTypes & ~WindowInsets.Type.ime();
             try {
                 mWmService.updateDisplayWindowRequestedVisibleTypes(mDisplayId,
-                        mRequestedVisibleTypes);
+                        mRequestedVisibleTypes, statsToken);
             } catch (RemoteException e) {
             }
         }
@@ -640,7 +643,7 @@
                         t.hide(animatingLeash);
                         removeImeSurface(mDisplayId);
                         if (android.view.inputmethod.Flags.refactorInsetsController()) {
-                            setVisibleDirectly(false /* visible */);
+                            setVisibleDirectly(false /* visible */, statsToken);
                         }
                         ImeTracker.forLogging().onHidden(mStatsToken);
                     } else if (mAnimationDirection == DIRECTION_SHOW && !mCancelled) {
@@ -669,13 +672,13 @@
             if (!android.view.inputmethod.Flags.refactorInsetsController() && !show) {
                 // When going away, queue up insets change first, otherwise any bounds changes
                 // can have a "flicker" of ime-provided insets.
-                setVisibleDirectly(false /* visible */);
+                setVisibleDirectly(false /* visible */, null /* statsToken */);
             }
             mAnimation.start();
             if (!android.view.inputmethod.Flags.refactorInsetsController() && show) {
                 // When showing away, queue up insets change last, otherwise any bounds changes
                 // can have a "flicker" of ime-provided insets.
-                setVisibleDirectly(true /* visible */);
+                setVisibleDirectly(true /* visible */, null /* statsToken */);
             }
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
index c4c177c..c45f09b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.common;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.os.RemoteException;
@@ -223,13 +224,14 @@
             }
         }
 
-        private void setImeInputTargetRequestedVisibility(boolean visible) {
+        private void setImeInputTargetRequestedVisibility(boolean visible,
+                @NonNull ImeTracker.Token statsToken) {
             CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
             if (listeners == null) {
                 return;
             }
             for (OnInsetsChangedListener listener : listeners) {
-                listener.setImeInputTargetRequestedVisibility(visible);
+                listener.setImeInputTargetRequestedVisibility(visible, statsToken);
             }
         }
 
@@ -276,10 +278,11 @@
             }
 
             @Override
-            public void setImeInputTargetRequestedVisibility(boolean visible)
+            public void setImeInputTargetRequestedVisibility(boolean visible,
+                    @NonNull ImeTracker.Token statsToken)
                     throws RemoteException {
                 mMainExecutor.execute(() -> {
-                    PerDisplay.this.setImeInputTargetRequestedVisibility(visible);
+                    PerDisplay.this.setImeInputTargetRequestedVisibility(visible, statsToken);
                 });
             }
         }
@@ -345,7 +348,10 @@
          * Called to set the requested visibility of the IME in DisplayImeController. Invoked by
          * {@link com.android.server.wm.DisplayContent.RemoteInsetsControlTarget}.
          * @param visible requested status of the IME
+         * @param statsToken the token tracking the current IME request
          */
-        default void setImeInputTargetRequestedVisibility(boolean visible) {}
+        default void setImeInputTargetRequestedVisibility(boolean visible,
+                @NonNull ImeTracker.Token statsToken) {
+        }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
index 9abf0f6..de5c834 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
@@ -33,6 +33,9 @@
 
     default void onRecentTaskListFrozenChanged(boolean frozen) { }
 
+    /** A task is removed from recents as a result of another task being added to recent tasks. */
+    default void onRecentTaskRemovedForAddTask(int taskId) { }
+
     @BinderThread
     default void onTaskStackChangedBackground() { }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
index d8859ba..4e1dec6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
@@ -59,6 +59,7 @@
     private static final int ON_TASK_LIST_FROZEN_UNFROZEN = 18;
     private static final int ON_TASK_DESCRIPTION_CHANGED = 19;
     private static final int ON_ACTIVITY_ROTATION = 20;
+    private static final int ON_RECENT_TASK_REMOVED_FOR_ADD_TASK = 21;
 
     /**
      * List of {@link TaskStackListenerCallback} registered from {@link #addListener}.
@@ -132,6 +133,11 @@
     }
 
     @Override
+    public void onRecentTaskRemovedForAddTask(int taskId) {
+        mMainHandler.obtainMessage(ON_RECENT_TASK_REMOVED_FOR_ADD_TASK, taskId).sendToTarget();
+    }
+
+    @Override
     public void onTaskStackChanged() {
         // Call the task changed callback for the non-ui thread listeners first. Copy to a set
         // of temp listeners so that we don't lock on mTaskStackListeners while calling all the
@@ -408,6 +414,13 @@
                     }
                     break;
                 }
+                case ON_RECENT_TASK_REMOVED_FOR_ADD_TASK: {
+                    final int taskId = (int) msg.obj;
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onRecentTaskRemovedForAddTask(taskId);
+                    }
+                    break;
+                }
                 case ON_TASK_DESCRIPTION_CHANGED: {
                     final ActivityManager.RunningTaskInfo
                             info = (ActivityManager.RunningTaskInfo) msg.obj;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/transition/TransitionStateHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/transition/TransitionStateHolder.kt
new file mode 100644
index 0000000..4dda2a8
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/transition/TransitionStateHolder.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 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.common.transition
+
+import com.android.wm.shell.dagger.WMSingleton
+import com.android.wm.shell.recents.RecentsTransitionHandler
+import com.android.wm.shell.recents.RecentsTransitionStateListener
+import com.android.wm.shell.recents.RecentsTransitionStateListener.RecentsTransitionState
+import com.android.wm.shell.recents.RecentsTransitionStateListener.isRunning
+import com.android.wm.shell.sysui.ShellInit
+import javax.inject.Inject
+
+/**
+ * Holder for the state of the transitions.
+ */
+@WMSingleton
+class TransitionStateHolder @Inject constructor(
+    shellInit: ShellInit,
+    private val recentsTransitionHandler: RecentsTransitionHandler
+) {
+
+    @Volatile
+    @RecentsTransitionState
+    private var recentsTransitionState: Int =
+        RecentsTransitionStateListener.TRANSITION_STATE_NOT_RUNNING
+
+    init {
+        shellInit.addInitCallback({ onInit() }, this)
+    }
+
+    fun isRecentsTransitionRunning(): Boolean = isRunning(recentsTransitionState)
+
+    private fun onInit() {
+        recentsTransitionHandler.addTransitionStateListener(
+            object : RecentsTransitionStateListener {
+                override fun onTransitionStateChanged(@RecentsTransitionState state: Int) {
+                    recentsTransitionState = state
+                }
+            }
+        )
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
index c99d9ba8..9d4b4bb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
@@ -54,6 +54,7 @@
 import com.android.wm.shell.compatui.api.CompatUIHandler;
 import com.android.wm.shell.compatui.api.CompatUIInfo;
 import com.android.wm.shell.compatui.impl.CompatUIEvents.SizeCompatRestartButtonClicked;
+import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.sysui.KeyguardChangeListener;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
@@ -65,6 +66,7 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Optional;
 import java.util.Set;
 import java.util.function.Consumer;
 import java.util.function.Function;
@@ -194,7 +196,7 @@
     private final CompatUIStatusManager mCompatUIStatusManager;
 
     @NonNull
-    private final IntPredicate mInDesktopModePredicate;
+    private final Optional<DesktopUserRepositories> mDesktopUserRepositories;
 
     public CompatUIController(@NonNull Context context,
             @NonNull ShellInit shellInit,
@@ -210,7 +212,7 @@
             @NonNull CompatUIShellCommandHandler compatUIShellCommandHandler,
             @NonNull AccessibilityManager accessibilityManager,
             @NonNull CompatUIStatusManager compatUIStatusManager,
-            @NonNull IntPredicate isDesktopModeEnablePredicate) {
+            @NonNull Optional<DesktopUserRepositories> desktopUserRepositories) {
         mContext = context;
         mShellController = shellController;
         mDisplayController = displayController;
@@ -226,7 +228,7 @@
         mDisappearTimeSupplier = flags -> accessibilityManager.getRecommendedTimeoutMillis(
                 DISAPPEAR_DELAY_MS, flags);
         mCompatUIStatusManager = compatUIStatusManager;
-        mInDesktopModePredicate = isDesktopModeEnablePredicate;
+        mDesktopUserRepositories = desktopUserRepositories;
         shellInit.addInitCallback(this::onInit, this);
     }
 
@@ -267,7 +269,6 @@
             updateActiveTaskInfo(taskInfo);
         }
 
-
         // We're showing the first reachability education so we ignore incoming TaskInfo
         // until the education flow has completed or we double tap. The double-tap
         // basically cancel all the onboarding flow. We don't have to ignore events in case
@@ -865,7 +866,11 @@
     }
 
     private boolean isInDesktopMode(@Nullable TaskInfo taskInfo) {
-        return taskInfo != null && Flags.skipCompatUiEducationInDesktopMode()
-                && mInDesktopModePredicate.test(taskInfo.displayId);
+        if (mDesktopUserRepositories.isEmpty() || taskInfo == null) {
+            return false;
+        }
+        boolean isDesktopModeShowing = mDesktopUserRepositories.get().getCurrent()
+                .getVisibleTaskCount(taskInfo.displayId) > 0;
+        return Flags.skipCompatUiEducationInDesktopMode() && isDesktopModeShowing;
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUILayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUILayout.java
index 49c2785..688f8ca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUILayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUILayout.java
@@ -68,7 +68,7 @@
 
     private void setViewVisibility(@IdRes int resId, boolean show) {
         final View view = findViewById(resId);
-        int visibility = show ? View.VISIBLE : View.INVISIBLE;
+        int visibility = show ? View.VISIBLE : View.GONE;
         if (view.getVisibility() == visibility) {
             return;
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayout.java
index fd1bbc4..b141beb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayout.java
@@ -100,7 +100,7 @@
 
     private void setViewVisibility(@IdRes int resId, boolean show) {
         final View view = findViewById(resId);
-        int visibility = show ? View.VISIBLE : View.INVISIBLE;
+        int visibility = show ? View.VISIBLE : View.GONE;
         if (view.getVisibility() == visibility) {
             return;
         }
@@ -171,7 +171,7 @@
         fadeOut.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
-                view.setVisibility(View.INVISIBLE);
+                view.setVisibility(View.GONE);
             }
         });
         fadeOut.start();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxController.kt
index 0ac7aff..523e2f5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxController.kt
@@ -18,133 +18,51 @@
 
 import android.graphics.Rect
 import android.view.SurfaceControl
-import com.android.internal.protolog.ProtoLog
-import com.android.wm.shell.dagger.WMSingleton
-import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT
-import javax.inject.Inject
+import android.view.SurfaceControl.Transaction
 
 /**
- * Component responsible for handling the lifecycle of the letterbox surfaces.
+ * Abstracts the component responsible to handle a single or multiple letterbox surfaces for a
+ * specific [Change].
  */
-@WMSingleton
-class LetterboxController @Inject constructor(
-    private val letterboxConfiguration: LetterboxConfiguration
-) {
-
-    companion object {
-        /*
-         * Letterbox surfaces need to stay below the activity layer which is 0.
-         */
-        // TODO(b/378673153): Consider adding this to [TaskConstants].
-        @JvmStatic
-        private val TASK_CHILD_LAYER_LETTERBOX_BACKGROUND = -1000
-        @JvmStatic
-        private val TAG = "LetterboxController"
-    }
-
-    private val letterboxMap = mutableMapOf<LetterboxKey, LetterboxItem>()
+interface LetterboxController {
 
     /**
      * Creates a Letterbox Surface for a given displayId/taskId if it doesn't exist.
      */
     fun createLetterboxSurface(
         key: LetterboxKey,
-        startTransaction: SurfaceControl.Transaction,
+        transaction: Transaction,
         parentLeash: SurfaceControl
-    ) {
-        letterboxMap.runOnItem(key, onMissed = { k, m ->
-            m[k] = LetterboxItem(
-                SurfaceControl.Builder()
-                    .setName("ShellLetterboxSurface-$key")
-                    .setHidden(true)
-                    .setColorLayer()
-                    .setParent(parentLeash)
-                    .setCallsite("LetterboxController-createLetterboxSurface")
-                    .build().apply {
-                        startTransaction.setLayer(
-                            this,
-                            TASK_CHILD_LAYER_LETTERBOX_BACKGROUND
-                        ).setColorSpaceAgnostic(this, true)
-                            .setColor(this, letterboxConfiguration.getBackgroundColorRgbArray())
-                    }
-            )
-        })
-    }
+    )
 
     /**
      * Invoked to destroy the surfaces for a letterbox session for given displayId/taskId.
      */
     fun destroyLetterboxSurface(
         key: LetterboxKey,
-        startTransaction: SurfaceControl.Transaction
-    ) {
-        letterboxMap.runOnItem(key, onFound = { item ->
-            item.fullWindowSurface?.run {
-                startTransaction.remove(this)
-            }
-        })
-        letterboxMap.remove(key)
-    }
+        transaction: Transaction
+    )
 
     /**
      * Invoked to show/hide the letterbox surfaces for given displayId/taskId.
      */
     fun updateLetterboxSurfaceVisibility(
         key: LetterboxKey,
-        startTransaction: SurfaceControl.Transaction,
-        visible: Boolean = true
-    ) {
-        letterboxMap.runOnItem(key, onFound = { item ->
-            item.fullWindowSurface?.run {
-                startTransaction.setVisibility(this, visible)
-            }
-        })
-    }
+        transaction: Transaction,
+        visible: Boolean
+    )
 
     /**
      * Updates the bounds for the letterbox surfaces for given displayId/taskId.
      */
     fun updateLetterboxSurfaceBounds(
         key: LetterboxKey,
-        startTransaction: SurfaceControl.Transaction,
-        bounds: Rect
-    ) {
-        letterboxMap.runOnItem(key, onFound = { item ->
-            item.fullWindowSurface?.run {
-                startTransaction.moveAndCrop(this, bounds)
-            }
-        })
-    }
+        transaction: Transaction,
+        taskBounds: Rect
+    )
 
-    /*
-     * Executes [onFound] on the [LetterboxItem] if present or [onMissed] if not present.
+    /**
+     * Utility method to dump the current state.
      */
-    private fun MutableMap<LetterboxKey, LetterboxItem>.runOnItem(
-        key: LetterboxKey,
-        onFound: (LetterboxItem) -> Unit = { _ -> },
-        onMissed: (
-            LetterboxKey,
-            MutableMap<LetterboxKey, LetterboxItem>
-        ) -> Unit = { _, _ -> }
-    ) {
-        this[key]?.let {
-            return onFound(it)
-        }
-        return onMissed(key, this)
-    }
-
-    fun dump() {
-        ProtoLog.v(WM_SHELL_APP_COMPAT, "%s: %s", TAG, "${letterboxMap.keys}")
-    }
-
-    private fun SurfaceControl.Transaction.moveAndCrop(
-        surface: SurfaceControl,
-        rect: Rect
-    ): SurfaceControl.Transaction =
-        setPosition(surface, rect.left.toFloat(), rect.top.toFloat())
-            .setWindowCrop(
-                surface,
-                rect.width(),
-                rect.height()
-            )
+    fun dump()
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxData.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxData.kt
index 98fd247..adb034c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxData.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxData.kt
@@ -16,10 +16,5 @@
 
 package com.android.wm.shell.compatui.letterbox
 
-import android.view.SurfaceControl
-
 // The key to use for identify the letterbox sessions.
-data class LetterboxKey(val displayId: Int, val taskId: Int)
-
-// Encapsulate the objects for the specific letterbox session.
-data class LetterboxItem(val fullWindowSurface: SurfaceControl?)
\ No newline at end of file
+data class LetterboxKey(val displayId: Int, val taskId: Int)
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxSurfaceBuilder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxSurfaceBuilder.kt
new file mode 100644
index 0000000..e88d91f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxSurfaceBuilder.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 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.compatui.letterbox
+
+import android.view.SurfaceControl
+import com.android.wm.shell.dagger.WMSingleton
+import javax.inject.Inject
+
+/**
+ * Component responsible for the actual creation of the Letterbox surfaces.
+ */
+@WMSingleton
+class LetterboxSurfaceBuilder @Inject constructor(
+    private val letterboxConfiguration: LetterboxConfiguration
+) {
+
+    companion object {
+        /*
+         * Letterbox surfaces need to stay below the activity layer which is 0.
+         */
+        // TODO(b/378673153): Consider adding this to [TaskConstants].
+        @JvmStatic
+        private val TASK_CHILD_LAYER_LETTERBOX_BACKGROUND = -1000
+    }
+
+    fun createSurface(
+        tx: SurfaceControl.Transaction,
+        parentLeash: SurfaceControl,
+        surfaceName: String,
+        callSite: String,
+        surfaceBuilder: SurfaceControl.Builder = SurfaceControl.Builder()
+    ) = surfaceBuilder
+        .setName(surfaceName)
+        .setHidden(true)
+        .setColorLayer()
+        .setParent(parentLeash)
+        .setCallsite(callSite)
+        .build().apply {
+            tx.setLayer(
+                this,
+                TASK_CHILD_LAYER_LETTERBOX_BACKGROUND
+            ).setColorSpaceAgnostic(this, true)
+                .setColor(this, letterboxConfiguration.getBackgroundColorRgbArray())
+        }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserver.kt
index 67429bd..8b830e7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserver.kt
@@ -22,6 +22,7 @@
 import android.window.TransitionInfo
 import com.android.internal.protolog.ProtoLog
 import com.android.window.flags.Flags.appCompatRefactoring
+import com.android.wm.shell.common.transition.TransitionStateHolder
 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT
 import com.android.wm.shell.shared.TransitionUtil.isClosingType
 import com.android.wm.shell.sysui.ShellInit
@@ -33,7 +34,8 @@
 class LetterboxTransitionObserver(
     shellInit: ShellInit,
     private val transitions: Transitions,
-    private val letterboxController: LetterboxController
+    private val letterboxController: LetterboxController,
+    private val transitionStateHolder: TransitionStateHolder
 ) : Transitions.TransitionObserver {
 
     companion object {
@@ -43,12 +45,7 @@
 
     init {
         if (appCompatRefactoring()) {
-            ProtoLog.v(
-                WM_SHELL_APP_COMPAT,
-                "%s: %s",
-                TAG,
-                "Initializing LetterboxTransitionObserver"
-            )
+            logV("Initializing LetterboxTransitionObserver")
             shellInit.addInitCallback({
                 transitions.registerObserver(this)
             }, this)
@@ -69,38 +66,45 @@
         for (change in info.changes) {
             change.taskInfo?.let { ti ->
                 val key = LetterboxKey(ti.displayId, ti.taskId)
-                if (isClosingType(change.mode)) {
-                    letterboxController.destroyLetterboxSurface(
-                        key,
-                        startTransaction
-                    )
-                } else {
-                    val isTopActivityLetterboxed = ti.appCompatTaskInfo.isTopActivityLetterboxed
-                    if (isTopActivityLetterboxed) {
-                        letterboxController.createLetterboxSurface(
-                            key,
-                            startTransaction,
-                            change.leash
-                        )
-                        letterboxController.updateLetterboxSurfaceBounds(
-                            key,
-                            startTransaction,
-                            Rect(
-                                change.endRelOffset.x,
-                                change.endRelOffset.y,
-                                change.endAbsBounds.width(),
-                                change.endAbsBounds.height()
+                val taskBounds = Rect(
+                    change.endRelOffset.x,
+                    change.endRelOffset.y,
+                    change.endAbsBounds.width(),
+                    change.endAbsBounds.height()
+                )
+                with(letterboxController) {
+                    // TODO(b/380274087) Handle return to home from a recents transition.
+                    if (isClosingType(change.mode) &&
+                        !transitionStateHolder.isRecentsTransitionRunning()) {
+                        // For the other types of close we need to check the recents.
+                        destroyLetterboxSurface(key, finishTransaction)
+                    } else {
+                        val isTopActivityLetterboxed = ti.appCompatTaskInfo.isTopActivityLetterboxed
+                        if (isTopActivityLetterboxed) {
+                            createLetterboxSurface(
+                                key,
+                                startTransaction,
+                                change.leash
                             )
+                            updateLetterboxSurfaceBounds(
+                                key,
+                                startTransaction,
+                                taskBounds
+                            )
+                        }
+                        updateLetterboxSurfaceVisibility(
+                            key,
+                            startTransaction,
+                            isTopActivityLetterboxed
                         )
                     }
-                    letterboxController.updateLetterboxSurfaceVisibility(
-                        key,
-                        startTransaction,
-                        isTopActivityLetterboxed
-                    )
+                    dump()
                 }
-                letterboxController.dump()
             }
         }
     }
+
+    private fun logV(msg: String) {
+        ProtoLog.v(WM_SHELL_APP_COMPAT, "%s: %s", TAG, msg)
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxController.kt
new file mode 100644
index 0000000..f21a727
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxController.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright 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.compatui.letterbox
+
+import android.graphics.Rect
+import android.view.SurfaceControl
+import android.view.SurfaceControl.Transaction
+import com.android.internal.protolog.ProtoLog
+import com.android.wm.shell.dagger.WMSingleton
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT
+import javax.inject.Inject
+
+/**
+ * Component responsible for handling the lifecycle of a single letterbox surface.
+ */
+@WMSingleton
+class SingleSurfaceLetterboxController @Inject constructor(
+    private val letterboxBuilder: LetterboxSurfaceBuilder
+) : LetterboxController {
+
+    companion object {
+        @JvmStatic
+        private val TAG = "LetterboxController"
+    }
+
+    private val letterboxMap = mutableMapOf<LetterboxKey, SurfaceControl>()
+
+    /**
+     * Creates a Letterbox Surface for a given displayId/taskId if it doesn't exist.
+     */
+    override fun createLetterboxSurface(
+        key: LetterboxKey,
+        transaction: Transaction,
+        parentLeash: SurfaceControl
+    ) {
+        letterboxMap.runOnItem(key, onMissed = { k, m ->
+            m[k] = letterboxBuilder.createSurface(
+                transaction,
+                parentLeash,
+                surfaceName = "ShellLetterboxSurface-$key",
+                callSite = "LetterboxController-createLetterboxSurface"
+            )
+        })
+    }
+
+    /**
+     * Invoked to destroy the surfaces for a letterbox session for given displayId/taskId.
+     */
+    override fun destroyLetterboxSurface(
+        key: LetterboxKey,
+        transaction: Transaction
+    ) {
+        letterboxMap.runOnItem(key, onFound = { item ->
+            item.run {
+                transaction.remove(this)
+            }
+        })
+        letterboxMap.remove(key)
+    }
+
+    /**
+     * Invoked to show/hide the letterbox surfaces for given displayId/taskId.
+     */
+    override fun updateLetterboxSurfaceVisibility(
+        key: LetterboxKey,
+        transaction: Transaction,
+        visible: Boolean
+    ) {
+        letterboxMap.runOnItem(key, onFound = { item ->
+            item.run {
+                transaction.setVisibility(this, visible)
+            }
+        })
+    }
+
+    /**
+     * Updates the bounds for the letterbox surfaces for given displayId/taskId.
+     */
+    override fun updateLetterboxSurfaceBounds(
+        key: LetterboxKey,
+        transaction: Transaction,
+        taskBounds: Rect
+    ) {
+        letterboxMap.runOnItem(key, onFound = { item ->
+            item.run {
+                transaction.moveAndCrop(this, taskBounds)
+            }
+        })
+    }
+
+    override fun dump() {
+        ProtoLog.v(WM_SHELL_APP_COMPAT, "%s: %s", TAG, "${letterboxMap.keys}")
+    }
+
+    /*
+     * Executes [onFound] on the [SurfaceControl] if present or [onMissed] if not present.
+     */
+    private fun MutableMap<LetterboxKey, SurfaceControl>.runOnItem(
+        key: LetterboxKey,
+        onFound: (SurfaceControl) -> Unit = { _ -> },
+        onMissed: (
+            LetterboxKey,
+            MutableMap<LetterboxKey, SurfaceControl>
+        ) -> Unit = { _, _ -> }
+    ) {
+        this[key]?.let {
+            return onFound(it)
+        }
+        return onMissed(key, this)
+    }
+
+    private fun Transaction.moveAndCrop(
+        surface: SurfaceControl,
+        rect: Rect
+    ): Transaction =
+        setPosition(surface, rect.left.toFloat(), rect.top.toFloat())
+            .setWindowCrop(
+                surface,
+                rect.width(),
+                rect.height()
+            )
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 6023750..47084e1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -87,8 +87,8 @@
 import com.android.wm.shell.compatui.impl.DefaultCompatUIRepository;
 import com.android.wm.shell.compatui.impl.DefaultComponentIdGenerator;
 import com.android.wm.shell.desktopmode.DesktopMode;
-import com.android.wm.shell.desktopmode.DesktopRepository;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
+import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
 import com.android.wm.shell.displayareahelper.DisplayAreaHelperController;
 import com.android.wm.shell.freeform.FreeformComponents;
@@ -138,7 +138,6 @@
 import dagger.Provides;
 
 import java.util.Optional;
-import java.util.function.IntPredicate;
 
 /**
  * Provides basic dependencies from {@link com.android.wm.shell}, these dependencies are only
@@ -267,7 +266,7 @@
             Lazy<CompatUIShellCommandHandler> compatUIShellCommandHandler,
             Lazy<AccessibilityManager> accessibilityManager,
             CompatUIRepository compatUIRepository,
-            Optional<DesktopRepository> desktopRepository,
+            Optional<DesktopUserRepositories> desktopUserRepositories,
             @NonNull CompatUIState compatUIState,
             @NonNull CompatUIComponentIdGenerator componentIdGenerator,
             @NonNull CompatUIComponentFactory compatUIComponentFactory,
@@ -280,10 +279,6 @@
                     new DefaultCompatUIHandler(compatUIRepository, compatUIState,
                             componentIdGenerator, compatUIComponentFactory, mainExecutor));
         }
-        final IntPredicate inDesktopModePredicate =
-                desktopRepository.<IntPredicate>map(modeTaskRepository -> displayId ->
-                        modeTaskRepository.getVisibleTaskCount(displayId) > 0)
-                            .orElseGet(() -> displayId -> false);
         return Optional.of(
                 new CompatUIController(
                         context,
@@ -300,7 +295,7 @@
                         compatUIShellCommandHandler.get(),
                         accessibilityManager.get(),
                         compatUIStatusManager,
-                        inDesktopModePredicate));
+                        desktopUserRepositories));
     }
 
     @WMSingleton
@@ -704,14 +699,14 @@
             ShellCommandHandler shellCommandHandler,
             TaskStackListenerImpl taskStackListener,
             ActivityTaskManager activityTaskManager,
-            Optional<DesktopRepository> desktopRepository,
+            Optional<DesktopUserRepositories> desktopUserRepositories,
             TaskStackTransitionObserver taskStackTransitionObserver,
             @ShellMainThread ShellExecutor mainExecutor
     ) {
         return Optional.ofNullable(
                 RecentTasksController.create(context, shellInit, shellController,
                         shellCommandHandler, taskStackListener, activityTaskManager,
-                        desktopRepository, taskStackTransitionObserver, mainExecutor));
+                        desktopUserRepositories, taskStackTransitionObserver, mainExecutor));
     }
 
     @BindsOptionalOf
@@ -799,10 +794,11 @@
             Transitions transitions,
             TaskStackListenerImpl taskStackListener,
             @ShellMainThread Handler mainHandler,
-            @ShellMainThread ShellExecutor mainExecutor) {
+            @ShellMainThread ShellExecutor mainExecutor,
+            FocusTransitionObserver focusTransitionObserver) {
         return new KeyguardTransitionHandler(
                 shellInit, shellController, displayController, transitions, taskStackListener,
-                mainHandler, mainExecutor);
+                mainHandler, mainExecutor, focusTransitionObserver);
     }
 
     @WMSingleton
@@ -1001,16 +997,16 @@
 
     @BindsOptionalOf
     @DynamicOverride
-    abstract DesktopRepository optionalDesktopRepository();
+    abstract DesktopUserRepositories optionalDesktopUserRepositories();
 
     @WMSingleton
     @Provides
-    static Optional<DesktopRepository> provideDesktopRepository(Context context,
-            @DynamicOverride Optional<Lazy<DesktopRepository>> desktopRepository) {
+    static Optional<DesktopUserRepositories> provideDesktopUserRepositories(Context context,
+            @DynamicOverride Optional<Lazy<DesktopUserRepositories>> desktopUserRepositories) {
         // Use optional-of-lazy for the dependency that this provider relies on.
         // Lazy ensures that this provider will not be the cause the dependency is created
         // when it will not be returned due to the condition below.
-        return desktopRepository.flatMap((lazy) -> {
+        return desktopUserRepositories.flatMap((lazy) -> {
             if (DesktopModeStatus.canEnterDesktopMode(context)) {
                 return Optional.of(lazy.get());
             }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 9ec80ec..0bf3d9b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -29,6 +29,7 @@
 import android.app.KeyguardManager;
 import android.content.Context;
 import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager;
 import android.hardware.input.InputManager;
 import android.os.Handler;
 import android.os.UserManager;
@@ -67,9 +68,11 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.common.transition.TransitionStateHolder;
 import com.android.wm.shell.compatui.letterbox.LetterboxCommandHandler;
 import com.android.wm.shell.compatui.letterbox.LetterboxController;
 import com.android.wm.shell.compatui.letterbox.LetterboxTransitionObserver;
+import com.android.wm.shell.compatui.letterbox.SingleSurfaceLetterboxController;
 import com.android.wm.shell.dagger.back.ShellBackAnimationModule;
 import com.android.wm.shell.dagger.pip.PipModule;
 import com.android.wm.shell.desktopmode.CloseDesktopTaskTransitionHandler;
@@ -83,11 +86,13 @@
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger;
 import com.android.wm.shell.desktopmode.DesktopModeKeyGestureHandler;
 import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver;
+import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger;
 import com.android.wm.shell.desktopmode.DesktopRepository;
 import com.android.wm.shell.desktopmode.DesktopTaskChangeListener;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
 import com.android.wm.shell.desktopmode.DesktopTasksLimiter;
 import com.android.wm.shell.desktopmode.DesktopTasksTransitionObserver;
+import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler;
 import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler;
 import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler;
@@ -147,6 +152,8 @@
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel;
 import com.android.wm.shell.windowdecor.WindowDecorViewModel;
 import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer;
+import com.android.wm.shell.windowdecor.common.viewhost.DefaultWindowDecorViewHostSupplier;
+import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier;
 import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationPromoController;
 import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationTooltipController;
 import com.android.wm.shell.windowdecor.tiling.DesktopTilingDecorViewModel;
@@ -334,6 +341,13 @@
         return new AdditionalSystemViewContainer.Factory();
     }
 
+    @WMSingleton
+    @Provides
+    static WindowDecorViewHostSupplier provideWindowDecorViewHostSupplier(
+            @ShellMainThread @NonNull CoroutineScope mainScope) {
+        return new DefaultWindowDecorViewHostSupplier(mainScope);
+    }
+
     //
     // Freeform
     //
@@ -359,7 +373,7 @@
             Context context,
             ShellInit shellInit,
             ShellTaskOrganizer shellTaskOrganizer,
-            Optional<DesktopRepository> desktopRepository,
+            Optional<DesktopUserRepositories> desktopUserRepositories,
             Optional<DesktopTasksController> desktopTasksController,
             LaunchAdjacentController launchAdjacentController,
             WindowDecorViewModel windowDecorViewModel,
@@ -371,7 +385,7 @@
                 context,
                 init,
                 shellTaskOrganizer,
-                desktopRepository,
+                desktopUserRepositories,
                 desktopTasksController,
                 launchAdjacentController,
                 windowDecorViewModel,
@@ -687,7 +701,7 @@
             DesktopModeDragAndDropTransitionHandler desktopModeDragAndDropTransitionHandler,
             ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler,
             DragToDesktopTransitionHandler dragToDesktopTransitionHandler,
-            @DynamicOverride DesktopRepository desktopRepository,
+            @DynamicOverride DesktopUserRepositories desktopUserRepositories,
             Optional<DesktopImmersiveController> desktopImmersiveController,
             DesktopModeLoggerTransitionObserver desktopModeLoggerTransitionObserver,
             LaunchAdjacentController launchAdjacentController,
@@ -701,6 +715,7 @@
             InputManager inputManager,
             FocusTransitionObserver focusTransitionObserver,
             DesktopModeEventLogger desktopModeEventLogger,
+            DesktopModeUiEventLogger desktopModeUiEventLogger,
             DesktopTilingDecorViewModel desktopTilingDecorViewModel) {
         return new DesktopTasksController(
                 context,
@@ -722,7 +737,7 @@
                 toggleResizeDesktopTaskTransitionHandler,
                 dragToDesktopTransitionHandler,
                 desktopImmersiveController.get(),
-                desktopRepository,
+                desktopUserRepositories,
                 recentsTransitionHandler,
                 multiInstanceHelper,
                 mainExecutor,
@@ -731,6 +746,7 @@
                 interactionJankMonitor,
                 mainHandler,
                 desktopModeEventLogger,
+                desktopModeUiEventLogger,
                 desktopTilingDecorViewModel);
     }
 
@@ -744,7 +760,7 @@
             ShellTaskOrganizer shellTaskOrganizer,
             ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler,
             ReturnToDragStartAnimator returnToDragStartAnimator,
-            @DynamicOverride DesktopRepository desktopRepository,
+            @DynamicOverride DesktopUserRepositories desktopUserRepositories,
             DesktopModeEventLogger desktopModeEventLogger) {
         return new DesktopTilingDecorViewModel(
                 context,
@@ -755,7 +771,7 @@
                 shellTaskOrganizer,
                 toggleResizeDesktopTaskTransitionHandler,
                 returnToDragStartAnimator,
-                desktopRepository,
+                desktopUserRepositories,
                 desktopModeEventLogger
         );
     }
@@ -763,10 +779,10 @@
     @WMSingleton
     @Provides
     static Optional<TaskChangeListener> provideDesktopTaskChangeListener(
-            Context context, @DynamicOverride DesktopRepository desktopRepository) {
+            Context context, @DynamicOverride DesktopUserRepositories desktopUserRepositories) {
         if (ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue()
                 && DesktopModeStatus.canEnterDesktopMode(context)) {
-            return Optional.of(new DesktopTaskChangeListener(desktopRepository));
+            return Optional.of(new DesktopTaskChangeListener(desktopUserRepositories));
         }
         return Optional.empty();
     }
@@ -776,7 +792,7 @@
     static Optional<DesktopTasksLimiter> provideDesktopTasksLimiter(
             Context context,
             Transitions transitions,
-            @DynamicOverride DesktopRepository desktopRepository,
+            @DynamicOverride DesktopUserRepositories desktopUserRepositories,
             ShellTaskOrganizer shellTaskOrganizer,
             InteractionJankMonitor interactionJankMonitor,
             @ShellMainThread Handler handler) {
@@ -789,7 +805,7 @@
         return Optional.of(
                 new DesktopTasksLimiter(
                         transitions,
-                        desktopRepository,
+                        desktopUserRepositories,
                         shellTaskOrganizer,
                         maxTaskLimit,
                         interactionJankMonitor,
@@ -803,7 +819,7 @@
             Context context,
             ShellInit shellInit,
             Transitions transitions,
-            @DynamicOverride DesktopRepository desktopRepository,
+            @DynamicOverride DesktopUserRepositories desktopUserRepositories,
             DisplayController displayController,
             ShellTaskOrganizer shellTaskOrganizer,
             ShellCommandHandler shellCommandHandler) {
@@ -812,7 +828,7 @@
                     new DesktopImmersiveController(
                             shellInit,
                             transitions,
-                            desktopRepository,
+                            desktopUserRepositories,
                             displayController,
                             shellTaskOrganizer,
                             shellCommandHandler));
@@ -850,14 +866,17 @@
             Optional<DesktopTasksController> desktopTasksController,
             InputManager inputManager,
             ShellTaskOrganizer shellTaskOrganizer,
-            FocusTransitionObserver focusTransitionObserver) {
+            FocusTransitionObserver focusTransitionObserver,
+            @ShellMainThread ShellExecutor mainExecutor,
+            DisplayController displayController) {
         if (DesktopModeStatus.canEnterDesktopMode(context) && useKeyGestureEventHandler()
                 && manageKeyGestures()
                 && (Flags.enableMoveToNextDisplayShortcut()
                 || Flags.enableTaskResizingKeyboardShortcuts())) {
             return Optional.of(new DesktopModeKeyGestureHandler(context,
                     desktopModeWindowDecorViewModel, desktopTasksController,
-                    inputManager, shellTaskOrganizer, focusTransitionObserver));
+                    inputManager, shellTaskOrganizer, focusTransitionObserver,
+                    mainExecutor, displayController));
         }
         return Optional.empty();
     }
@@ -874,13 +893,14 @@
             ShellCommandHandler shellCommandHandler,
             IWindowManager windowManager,
             ShellTaskOrganizer taskOrganizer,
-            @DynamicOverride DesktopRepository desktopRepository,
+            @DynamicOverride DesktopUserRepositories desktopUserRepositories,
             DisplayController displayController,
             ShellController shellController,
             DisplayInsetsController displayInsetsController,
             SyncTransactionQueue syncQueue,
             Transitions transitions,
             Optional<DesktopTasksController> desktopTasksController,
+            Optional<DesktopImmersiveController> desktopImmersiveController,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
             InteractionJankMonitor interactionJankMonitor,
             AppToWebGenericLinksParser genericLinksParser,
@@ -892,20 +912,22 @@
             WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
             Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
             FocusTransitionObserver focusTransitionObserver,
-            DesktopModeEventLogger desktopModeEventLogger
+            DesktopModeEventLogger desktopModeEventLogger,
+            DesktopModeUiEventLogger desktopModeUiEventLogger
     ) {
         if (!DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(context)) {
             return Optional.empty();
         }
         return Optional.of(new DesktopModeWindowDecorViewModel(context, shellExecutor, mainHandler,
                 mainChoreographer, bgExecutor, shellInit, shellCommandHandler, windowManager,
-                taskOrganizer, desktopRepository, displayController, shellController,
+                taskOrganizer, desktopUserRepositories, displayController, shellController,
                 displayInsetsController, syncQueue, transitions, desktopTasksController,
+                desktopImmersiveController.get(),
                 rootTaskDisplayAreaOrganizer, interactionJankMonitor, genericLinksParser,
                 assistContentRequester, multiInstanceHelper, desktopTasksLimiter,
                 appHandleEducationController, appToWebEducationController,
                 windowDecorCaptionHandleRepository, activityOrientationChangeHandler,
-                focusTransitionObserver, desktopModeEventLogger));
+                focusTransitionObserver, desktopModeEventLogger, desktopModeUiEventLogger));
     }
 
     @WMSingleton
@@ -916,7 +938,7 @@
             @ShellAnimationThread ShellExecutor animExecutor,
             ShellInit shellInit,
             Transitions transitions,
-            @DynamicOverride DesktopRepository desktopRepository) {
+            @DynamicOverride DesktopUserRepositories desktopUserRepositories) {
         if (!DesktopModeStatus.canEnterDesktopMode(context)
                 || !ENABLE_DESKTOP_WINDOWING_MODALS_POLICY.isTrue()
                 || !Flags.enableDesktopSystemDialogsTransitions()) {
@@ -925,7 +947,7 @@
         return Optional.of(
                 new SystemModalsTransitionHandler(
                         context, mainExecutor, animExecutor, shellInit, transitions,
-                        desktopRepository));
+                        desktopUserRepositories));
     }
 
     @WMSingleton
@@ -984,16 +1006,17 @@
     @WMSingleton
     @Provides
     @DynamicOverride
-    static DesktopRepository provideDesktopRepository(
+    static DesktopUserRepositories provideDesktopUserRepositories(
             Context context,
             ShellInit shellInit,
             DesktopPersistentRepository desktopPersistentRepository,
             DesktopRepositoryInitializer desktopRepositoryInitializer,
-            @ShellMainThread CoroutineScope mainScope
+            @ShellMainThread CoroutineScope mainScope,
+            UserManager userManager
     ) {
-        return new DesktopRepository(context, shellInit, desktopPersistentRepository,
+        return new DesktopUserRepositories(context, shellInit, desktopPersistentRepository,
                 desktopRepositoryInitializer,
-                mainScope);
+                mainScope, userManager);
     }
 
     @WMSingleton
@@ -1004,7 +1027,7 @@
             ShellTaskOrganizer shellTaskOrganizer,
             TaskStackListenerImpl taskStackListener,
             ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler,
-            @DynamicOverride DesktopRepository desktopRepository) {
+            @DynamicOverride DesktopUserRepositories desktopUserRepositories) {
         if (DesktopModeStatus.canEnterDesktopMode(context)) {
             return Optional.of(
                     new DesktopActivityOrientationChangeHandler(
@@ -1013,7 +1036,7 @@
                             shellTaskOrganizer,
                             taskStackListener,
                             toggleResizeDesktopTaskTransitionHandler,
-                            desktopRepository));
+                            desktopUserRepositories));
         }
         return Optional.empty();
     }
@@ -1022,12 +1045,12 @@
     @Provides
     static Optional<DesktopTasksTransitionObserver> provideDesktopTasksTransitionObserver(
             Context context,
-            Optional<DesktopRepository> desktopRepository,
+            Optional<DesktopUserRepositories> desktopUserRepositories,
             Transitions transitions,
             ShellTaskOrganizer shellTaskOrganizer,
             Optional<DesktopMixedTransitionHandler> desktopMixedTransitionHandler,
             ShellInit shellInit) {
-        return desktopRepository.flatMap(
+        return desktopUserRepositories.flatMap(
                 repository ->
                         Optional.of(
                                 new DesktopTasksTransitionObserver(
@@ -1044,7 +1067,7 @@
     static Optional<DesktopMixedTransitionHandler> provideDesktopMixedTransitionHandler(
             Context context,
             Transitions transitions,
-            @DynamicOverride DesktopRepository desktopRepository,
+            @DynamicOverride DesktopUserRepositories desktopUserRepositories,
             FreeformTaskTransitionHandler freeformTaskTransitionHandler,
             CloseDesktopTaskTransitionHandler closeDesktopTaskTransitionHandler,
             Optional<DesktopImmersiveController> desktopImmersiveController,
@@ -1062,7 +1085,7 @@
                 new DesktopMixedTransitionHandler(
                         context,
                         transitions,
-                        desktopRepository,
+                        desktopUserRepositories,
                         freeformTaskTransitionHandler,
                         closeDesktopTaskTransitionHandler,
                         desktopImmersiveController.get(),
@@ -1230,6 +1253,15 @@
                 mainScope);
     }
 
+    @WMSingleton
+    @Provides
+    static DesktopModeUiEventLogger provideDesktopUiEventLogger(
+            UiEventLogger uiEventLogger,
+            PackageManager packageManager
+    ) {
+        return new DesktopModeUiEventLogger(uiEventLogger, packageManager);
+    }
+
     //
     // Drag and drop
     //
@@ -1298,8 +1330,15 @@
     static LetterboxTransitionObserver provideLetterboxTransitionObserver(
             @NonNull ShellInit shellInit,
             @NonNull Transitions transitions,
-            @NonNull LetterboxController letterboxController
+            @NonNull LetterboxController letterboxController,
+            @NonNull TransitionStateHolder transitionStateHolder
     ) {
-        return new LetterboxTransitionObserver(shellInit, transitions, letterboxController);
+        return new LetterboxTransitionObserver(shellInit, transitions, letterboxController,
+                transitionStateHolder);
     }
+
+    @WMSingleton
+    @Binds
+    abstract LetterboxController bindsLetterboxController(
+            SingleSurfaceLetterboxController letterboxController);
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
index 3cd5df3..cfdfe3d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
@@ -42,7 +42,7 @@
 import com.android.wm.shell.common.pip.SizeSpecSource;
 import com.android.wm.shell.dagger.WMShellBaseModule;
 import com.android.wm.shell.dagger.WMSingleton;
-import com.android.wm.shell.desktopmode.DesktopRepository;
+import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.onehanded.OneHandedController;
 import com.android.wm.shell.pip.PipAnimationController;
 import com.android.wm.shell.pip.PipParamsChangedForwarder;
@@ -171,7 +171,7 @@
             PipParamsChangedForwarder pipParamsChangedForwarder,
             Optional<SplitScreenController> splitScreenControllerOptional,
             Optional<PipPerfHintController> pipPerfHintControllerOptional,
-            Optional<DesktopRepository> desktopRepositoryOptional,
+            Optional<DesktopUserRepositories> desktopUserRepositoriesOptional,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
             DisplayController displayController,
             PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
@@ -181,7 +181,7 @@
                 pipBoundsAlgorithm, menuPhoneController, pipAnimationController,
                 pipSurfaceTransactionHelper, pipTransitionController, pipParamsChangedForwarder,
                 splitScreenControllerOptional, pipPerfHintControllerOptional,
-                desktopRepositoryOptional, rootTaskDisplayAreaOrganizer, displayController,
+                desktopUserRepositoriesOptional, rootTaskDisplayAreaOrganizer, displayController,
                 pipUiEventLogger, shellTaskOrganizer, mainExecutor);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
index 3508ece..3a99619 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.os.Handler;
 
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayInsetsController;
@@ -38,6 +39,7 @@
 import com.android.wm.shell.common.pip.SizeSpecSource;
 import com.android.wm.shell.dagger.WMShellBaseModule;
 import com.android.wm.shell.dagger.WMSingleton;
+import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.pip2.phone.PhonePipMenuController;
 import com.android.wm.shell.pip2.phone.PipController;
 import com.android.wm.shell.pip2.phone.PipMotionHelper;
@@ -128,8 +130,11 @@
     static PipScheduler providePipScheduler(Context context,
             PipBoundsState pipBoundsState,
             @ShellMainThread ShellExecutor mainExecutor,
-            PipTransitionState pipTransitionState) {
-        return new PipScheduler(context, pipBoundsState, mainExecutor, pipTransitionState);
+            PipTransitionState pipTransitionState,
+            Optional<DesktopUserRepositories> desktopUserRepositoriesOptional,
+            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
+        return new PipScheduler(context, pipBoundsState, mainExecutor, pipTransitionState,
+                desktopUserRepositoriesOptional, rootTaskDisplayAreaOrganizer);
     }
 
     @WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandler.kt
index 606aa6c..c0bf40b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandler.kt
@@ -39,7 +39,7 @@
     private val shellTaskOrganizer: ShellTaskOrganizer,
     private val taskStackListener: TaskStackListenerImpl,
     private val resizeHandler: ToggleResizeDesktopTaskTransitionHandler,
-    private val taskRepository: DesktopRepository,
+    private val desktopUserRepositories: DesktopUserRepositories,
 ) {
 
     init {
@@ -81,7 +81,9 @@
     ) {
         if (!Flags.respectOrientationChangeForUnresizeable()) return
         val task = shellTaskOrganizer.getRunningTaskInfo(taskId) ?: return
-        if (!isDesktopModeShowing(task.displayId) || !task.isFreeform || task.isResizeable) return
+        val taskRepository = desktopUserRepositories.current
+        val isDesktopModeShowing = taskRepository.getVisibleTaskCount(task.displayId) > 0
+        if (!isDesktopModeShowing || !task.isFreeform || task.isResizeable) return
 
         val taskBounds = task.configuration.windowConfiguration.bounds
         val taskHeight = taskBounds.height()
@@ -106,7 +108,4 @@
             resizeHandler.startTransition(wct)
         }
     }
-
-    private fun isDesktopModeShowing(displayId: Int): Boolean =
-        taskRepository.getVisibleTaskCount(displayId) > 0
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt
index 4723eb2..79be698 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt
@@ -50,7 +50,7 @@
 class DesktopImmersiveController(
     shellInit: ShellInit,
     private val transitions: Transitions,
-    private val desktopRepository: DesktopRepository,
+    private val desktopUserRepositories: DesktopUserRepositories,
     private val displayController: DisplayController,
     private val shellTaskOrganizer: ShellTaskOrganizer,
     private val shellCommandHandler: ShellCommandHandler,
@@ -60,14 +60,14 @@
     constructor(
         shellInit: ShellInit,
         transitions: Transitions,
-        desktopRepository: DesktopRepository,
+        desktopUserRepositories: DesktopUserRepositories,
         displayController: DisplayController,
         shellTaskOrganizer: ShellTaskOrganizer,
         shellCommandHandler: ShellCommandHandler,
     ) : this(
         shellInit,
         transitions,
-        desktopRepository,
+        desktopUserRepositories,
         displayController,
         shellTaskOrganizer,
         shellCommandHandler,
@@ -99,6 +99,7 @@
 
     /** Starts a transition to enter full immersive state inside the desktop. */
     fun moveTaskToImmersive(taskInfo: RunningTaskInfo) {
+        check(taskInfo.isFreeform) { "Task must already be in freeform" }
         if (inProgress) {
             logV(
                 "Cannot start entry because transition(s) already in progress: %s",
@@ -121,6 +122,7 @@
 
     /** Starts a transition to move an immersive task out of immersive. */
     fun moveTaskToNonImmersive(taskInfo: RunningTaskInfo, reason: ExitReason) {
+        check(taskInfo.isFreeform) { "Task must already be in freeform" }
         if (inProgress) {
             logV(
                 "Cannot start exit because transition(s) already in progress: %s",
@@ -175,8 +177,9 @@
         reason: ExitReason,
     ): ExitResult {
         if (!Flags.enableFullyImmersiveInDesktop()) return ExitResult.NoExit
-        val immersiveTask = desktopRepository.getTaskInFullImmersiveState(displayId)
-            ?: return ExitResult.NoExit
+        val immersiveTask =
+            desktopUserRepositories.current.getTaskInFullImmersiveState(displayId)
+                ?: return ExitResult.NoExit
         if (immersiveTask == excludeTaskId) {
             return ExitResult.NoExit
         }
@@ -208,7 +211,7 @@
         reason: ExitReason,
     ): ExitResult {
         if (!Flags.enableFullyImmersiveInDesktop()) return ExitResult.NoExit
-        if (desktopRepository.isTaskInFullImmersiveState(taskInfo.taskId)) {
+        if (desktopUserRepositories.current.isTaskInFullImmersiveState(taskInfo.taskId)) {
             // A full immersive task is being minimized, make sure the immersive state is broken
             // (i.e. resize back to max bounds).
             wct.setBounds(taskInfo.token, getExitDestinationBounds(taskInfo))
@@ -375,6 +378,7 @@
         startTransaction: SurfaceControl.Transaction,
         finishTransaction: SurfaceControl.Transaction,
     ) {
+        val desktopRepository: DesktopRepository = desktopUserRepositories.current
         // Check if this is a pending external exit transition.
         val pendingExit = pendingExternalExitTransitions
             .firstOrNull { pendingExit -> pendingExit.transition == transition }
@@ -410,6 +414,7 @@
             }
             val startBounds = immersiveChange.startAbsBounds
             logV("Direct move for task#%d in %s direction verified", state.taskId, state.direction)
+
             when (state.direction) {
                 Direction.ENTER -> {
                     desktopRepository.setTaskInFullImmersiveState(
@@ -482,7 +487,8 @@
         val displayLayout = displayController.getDisplayLayout(taskInfo.displayId)
             ?: error("Expected non-null display layout for displayId: ${taskInfo.displayId}")
         return if (Flags.enableRestoreToPreviousSizeFromDesktopImmersive()) {
-            desktopRepository.removeBoundsBeforeFullImmersive(taskInfo.taskId)
+            desktopUserRepositories.current
+                    .removeBoundsBeforeFullImmersive(taskInfo.taskId)
                 ?: if (ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()) {
                     calculateInitialBounds(displayLayout, taskInfo)
                 } else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt
index 82c2ebc..96bbd58 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt
@@ -49,7 +49,7 @@
 class DesktopMixedTransitionHandler(
     private val context: Context,
     private val transitions: Transitions,
-    private val desktopRepository: DesktopRepository,
+    private val desktopUserRepositories: DesktopUserRepositories,
     private val freeformTaskTransitionHandler: FreeformTaskTransitionHandler,
     private val closeDesktopTaskTransitionHandler: CloseDesktopTaskTransitionHandler,
     private val desktopImmersiveController: DesktopImmersiveController,
@@ -405,7 +405,7 @@
 
     private fun isLastDesktopTask(change: TransitionInfo.Change): Boolean =
         change.taskInfo?.let {
-            desktopRepository.getExpandedTaskCount(it.displayId) == 1
+            desktopUserRepositories.getProfile(it.userId).getExpandedTaskCount(it.displayId) == 1
         } ?: false
 
     private fun findCloseDesktopTaskChange(info: TransitionInfo): TransitionInfo.Change? {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
index b4eac7a..dc23128 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
@@ -446,6 +446,7 @@
             val displayArea: Int?,
         )
 
+        @JvmStatic
         fun getInputMethodFromMotionEvent(e: MotionEvent?): InputMethod {
             if (e == null) return InputMethod.UNKNOWN_INPUT_METHOD
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
index 114563a..250e177 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
@@ -30,9 +30,12 @@
 import android.content.Context
 import com.android.hardware.input.Flags.manageKeyGestures
 import com.android.window.flags.Flags.enableTaskResizingKeyboardShortcuts
-import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction
 import com.android.wm.shell.transition.FocusTransitionObserver
 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
+import com.android.wm.shell.shared.annotations.ShellMainThread
 import java.util.Optional
 
 /**
@@ -45,7 +48,9 @@
     inputManager: InputManager,
     private val shellTaskOrganizer: ShellTaskOrganizer,
     private val focusTransitionObserver: FocusTransitionObserver,
-    ) : KeyGestureEventHandler {
+    @ShellMainThread private val mainExecutor: ShellExecutor,
+    private val displayController: DisplayController,
+) : KeyGestureEventHandler {
 
     init {
         inputManager.registerKeyGestureEventHandler(this)
@@ -69,42 +74,55 @@
             KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW -> {
                 logV("Key gesture SNAP_LEFT_FREEFORM_WINDOW is handled")
                 getGloballyFocusedFreeformTask()?.let {
-                    desktopModeWindowDecorViewModel.get().onSnapResize(
-                        it.taskId,
-                        true,
-                        DesktopModeEventLogger.Companion.InputMethod.KEYBOARD
-                    )
+                    mainExecutor.execute {
+                        desktopModeWindowDecorViewModel.get().onSnapResize(
+                            it.taskId,
+                            true,
+                            DesktopModeEventLogger.Companion.InputMethod.KEYBOARD,
+                            /* fromMenu= */ false
+                        )
+                    }
                 }
                 return true
             }
             KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW -> {
                 logV("Key gesture SNAP_RIGHT_FREEFORM_WINDOW is handled")
                 getGloballyFocusedFreeformTask()?.let {
-                    desktopModeWindowDecorViewModel.get().onSnapResize(
-                        it.taskId,
-                        false,
-                        DesktopModeEventLogger.Companion.InputMethod.KEYBOARD
-                    )
+                    mainExecutor.execute {
+                        desktopModeWindowDecorViewModel.get().onSnapResize(
+                            it.taskId,
+                            false,
+                            DesktopModeEventLogger.Companion.InputMethod.KEYBOARD,
+                            /* fromMenu= */ false
+                        )
+                    }
                 }
                 return true
             }
             KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW -> {
                 logV("Key gesture TOGGLE_MAXIMIZE_FREEFORM_WINDOW is handled")
-                getGloballyFocusedFreeformTask()?.let {
-                    desktopTasksController.get().toggleDesktopTaskSize(
-                        it,
-                        ResizeTrigger.MAXIMIZE_MENU,
-                        null,
-                    )
+                getGloballyFocusedFreeformTask()?.let { taskInfo ->
+                    mainExecutor.execute {
+                        desktopTasksController.get().toggleDesktopTaskSize(
+                            taskInfo,
+                            ToggleTaskSizeInteraction(
+                                isMaximized = isTaskMaximized(taskInfo, displayController),
+                                source = ToggleTaskSizeInteraction.Source.KEYBOARD_SHORTCUT,
+                                inputMethod = DesktopModeEventLogger.Companion.InputMethod.KEYBOARD
+                            )
+                        )
+                    }
                 }
                 return true
             }
             KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW -> {
                 logV("Key gesture MINIMIZE_FREEFORM_WINDOW is handled")
                 getGloballyFocusedFreeformTask()?.let {
-                    desktopTasksController.get().minimizeTask(
-                        it,
-                    )
+                    mainExecutor.execute {
+                        desktopTasksController.get().minimizeTask(
+                            it,
+                        )
+                    }
                 }
                 return true
             }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLogger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLogger.kt
index a9d4e5f..3821998 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLogger.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLogger.kt
@@ -16,22 +16,23 @@
 
 package com.android.wm.shell.desktopmode
 
-import android.util.Log
+import android.app.ActivityManager.RunningTaskInfo
+import android.content.pm.PackageManager
 import com.android.internal.logging.InstanceId
 import com.android.internal.logging.InstanceIdSequence
 import com.android.internal.logging.UiEvent
 import com.android.internal.logging.UiEventLogger
-import com.android.wm.shell.dagger.WMSingleton
-import javax.inject.Inject
+import com.android.internal.logging.UiEventLogger.UiEventEnum
+import com.android.internal.protolog.ProtoLog
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
 
 /** Log Aster UIEvents for desktop windowing mode. */
-@WMSingleton
-class DesktopModeUiEventLogger
-@Inject
-constructor(
-    private val mUiEventLogger: UiEventLogger,
-    private val mInstanceIdSequence: InstanceIdSequence
+class DesktopModeUiEventLogger(
+    private val uiEventLogger: UiEventLogger,
+    private val packageManager: PackageManager,
 ) {
+    private val instanceIdSequence = InstanceIdSequence(Integer.MAX_VALUE)
+
     /**
      * Logs an event for a CUI, on a particular package.
      *
@@ -41,14 +42,25 @@
      */
     fun log(uid: Int, packageName: String, event: DesktopUiEventEnum) {
         if (packageName.isEmpty() || uid < 0) {
-            Log.d(TAG, "Skip logging since package name is empty or bad uid")
+            logD("Skip logging since package name is empty or bad uid")
             return
         }
-        mUiEventLogger.log(event, uid, packageName)
+        uiEventLogger.log(event, uid, packageName)
+    }
+
+    /** Logs an event for a CUI on a particular task. */
+    fun log(taskInfo: RunningTaskInfo, event: DesktopUiEventEnum) {
+        val packageName = taskInfo.baseActivity?.packageName
+        if (packageName == null) {
+            logD("Skip logging due to null base activity")
+            return
+        }
+        val uid = getUid(packageName, taskInfo.userId)
+        log(uid, packageName, event)
     }
 
     /** Retrieves a new instance id for a new interaction. */
-    fun getNewInstanceId(): InstanceId = mInstanceIdSequence.newInstanceId()
+    fun getNewInstanceId(): InstanceId = instanceIdSequence.newInstanceId()
 
     /**
      * Logs an event as part of a particular CUI, on a particular package.
@@ -66,28 +78,79 @@
         event: DesktopUiEventEnum
     ) {
         if (packageName.isEmpty() || uid < 0) {
-            Log.d(TAG, "Skip logging since package name is empty or bad uid")
+            logD("Skip logging since package name is empty or bad uid")
             return
         }
-        mUiEventLogger.logWithInstanceId(event, uid, packageName, instanceId)
+        uiEventLogger.logWithInstanceId(event, uid, packageName, instanceId)
+    }
+
+    private fun getUid(packageName: String, userId: Int): Int = try {
+        packageManager.getApplicationInfoAsUser(packageName, /* flags= */ 0, userId).uid
+    } catch (e: PackageManager.NameNotFoundException) {
+        INVALID_PACKAGE_UID
+    }
+
+    private fun logD(msg: String, vararg arguments: Any?) {
+        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
+    }
+
+    /** Enums for logging desktop windowing mode UiEvents. */
+    enum class DesktopUiEventEnum(private val mId: Int) : UiEventEnum {
+
+        @UiEvent(doc = "Resize the window in desktop windowing mode by dragging the edge")
+        DESKTOP_WINDOW_EDGE_DRAG_RESIZE(1721),
+        @UiEvent(doc = "Resize the window in desktop windowing mode by dragging the corner")
+        DESKTOP_WINDOW_CORNER_DRAG_RESIZE(1722),
+        @UiEvent(doc = "Tap on the window header maximize button in desktop windowing mode")
+        DESKTOP_WINDOW_MAXIMIZE_BUTTON_TAP(1723),
+        @UiEvent(doc = "Tap on the window header restore button in desktop windowing mode")
+        DESKTOP_WINDOW_RESTORE_BUTTON_TAP(2017),
+        @UiEvent(doc = "Double tap on window header to maximize it in desktop windowing mode")
+        DESKTOP_WINDOW_HEADER_DOUBLE_TAP_TO_MAXIMIZE(1724),
+        @UiEvent(doc = "Double tap on window header to restore from maximize in desktop windowing")
+        DESKTOP_WINDOW_HEADER_DOUBLE_TAP_TO_RESTORE(2018),
+        @UiEvent(doc = "Tap on the window Handle to open the Handle Menu")
+        DESKTOP_WINDOW_APP_HANDLE_TAP(1998),
+        @UiEvent(doc = "Tap on the desktop mode option under app handle menu")
+        DESKTOP_WINDOW_APP_HANDLE_MENU_TAP_TO_DESKTOP_MODE(1999),
+        @UiEvent(doc = "Tap on the split screen option under app handle menu")
+        DESKTOP_WINDOW_APP_HANDLE_MENU_TAP_TO_SPLIT_SCREEN(2000),
+        @UiEvent(doc = "Tap on the full screen option under app handle menu")
+        DESKTOP_WINDOW_APP_HANDLE_MENU_TAP_TO_FULL_SCREEN(2001),
+        @UiEvent(doc = "When user successfully drags the app handle to desktop mode")
+        DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_DESKTOP_MODE(2002),
+        @UiEvent(doc = "When user successfully drags the app handle to split screen")
+        DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_SPLIT_SCREEN(2003),
+        @UiEvent(doc = "When user successfully drags the app handle to full screen")
+        DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_FULL_SCREEN(2004),
+        @UiEvent(doc = "Drag the window header to the top to switch to full screen mode")
+        DESKTOP_WINDOW_APP_HEADER_DRAG_TO_FULL_SCREEN(2005),
+        @UiEvent(doc = "Drag the window header to an edge to tile it to the left side")
+        DESKTOP_WINDOW_APP_HEADER_DRAG_TO_TILE_TO_LEFT(2006),
+        @UiEvent(doc = "Drag the window header to an edge to tile it to the right side")
+        DESKTOP_WINDOW_APP_HEADER_DRAG_TO_TILE_TO_RIGHT(2007),
+        @UiEvent(doc = "Hover or long press the maximize button to reveal the menu")
+        DESKTOP_WINDOW_MAXIMIZE_BUTTON_REVEAL_MENU(2015),
+        @UiEvent(doc = "Tap on the maximize option in the maximize button menu")
+        DESKTOP_WINDOW_MAXIMIZE_BUTTON_MENU_TAP_TO_MAXIMIZE(2009),
+        @UiEvent(doc = "Tap on the immersive option in the maximize button menu")
+        DESKTOP_WINDOW_MAXIMIZE_BUTTON_MENU_TAP_TO_IMMERSIVE(2010),
+        @UiEvent(doc = "Tap on the restore option in the maximize button menu")
+        DESKTOP_WINDOW_MAXIMIZE_BUTTON_MENU_TAP_TO_RESTORE(2011),
+        @UiEvent(doc = "Tap on the tile to left option in the maximize button menu")
+        DESKTOP_WINDOW_MAXIMIZE_BUTTON_MENU_TAP_TO_TILE_TO_LEFT(2012),
+        @UiEvent(doc = "Tap on the tile to right option in the maximize button menu")
+        DESKTOP_WINDOW_MAXIMIZE_BUTTON_MENU_TAP_TO_TILE_TO_RIGHT(2013),
+        @UiEvent(doc = "Moving the desktop window by dragging the header")
+        DESKTOP_WINDOW_MOVE_BY_HEADER_DRAG(2021),
+        @UiEvent(doc = "Double tap on the window header to refocus a desktop window")
+        DESKTOP_WINDOW_HEADER_TAP_TO_REFOCUS(2022);
+
+        override fun getId(): Int = mId
     }
 
     companion object {
-        /** Enums for logging desktop windowing mode UiEvents. */
-        enum class DesktopUiEventEnum(private val mId: Int) : UiEventLogger.UiEventEnum {
-
-            @UiEvent(doc = "Resize the window in desktop windowing mode by dragging the edge")
-            DESKTOP_WINDOW_EDGE_DRAG_RESIZE(1721),
-            @UiEvent(doc = "Resize the window in desktop windowing mode by dragging the corner")
-            DESKTOP_WINDOW_CORNER_DRAG_RESIZE(1722),
-            @UiEvent(doc = "Tap on the window header maximize button in desktop windowing mode")
-            DESKTOP_WINDOW_MAXIMIZE_BUTTON_TAP(1723),
-            @UiEvent(doc = "Double tap on window header to maximize it in desktop windowing mode")
-            DESKTOP_WINDOW_HEADER_DOUBLE_TAP_TO_MAXIMIZE(1724);
-
-            override fun getId(): Int = mId
-        }
-
         private const val TAG = "DesktopModeUiEventLogger"
+        private const val INVALID_PACKAGE_UID = -1
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
index c7cf310..42c3b1c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
@@ -28,6 +28,7 @@
 import android.graphics.Rect
 import android.os.SystemProperties
 import android.util.Size
+import com.android.wm.shell.common.DisplayController
 import com.android.wm.shell.common.DisplayLayout
 
 val DESKTOP_MODE_INITIAL_BOUNDS_SCALE: Float =
@@ -211,6 +212,31 @@
         minOf(appBounds.height(), appBounds.width()).toFloat()
 }
 
+/** Returns whether the task is maximized. */
+fun isTaskMaximized(
+    taskInfo: RunningTaskInfo,
+    displayController: DisplayController
+): Boolean {
+    val displayLayout = displayController.getDisplayLayout(taskInfo.displayId)
+        ?: error("Could not get display layout for display=${taskInfo.displayId}")
+    val stableBounds = Rect()
+    displayLayout.getStableBounds(stableBounds)
+    return isTaskMaximized(taskInfo, stableBounds)
+}
+
+/** Returns whether the task is maximized. */
+fun isTaskMaximized(
+    taskInfo: RunningTaskInfo,
+    stableBounds: Rect
+): Boolean {
+    val currentTaskBounds = taskInfo.configuration.windowConfiguration.bounds
+    return if (taskInfo.isResizeable) {
+        isTaskBoundsEqual(currentTaskBounds, stableBounds)
+    } else {
+        isTaskWidthOrHeightEqual(currentTaskBounds, stableBounds)
+    }
+}
+
 /** Returns true if task's width or height is maximized else returns false. */
 fun isTaskWidthOrHeightEqual(taskBounds: Rect, stableBounds: Rect): Boolean {
     return taskBounds.width() == stableBounds.width() ||
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
index 09e77fe..80d8ecc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
@@ -120,6 +120,7 @@
     private View mView;
     private IndicatorType mCurrentType;
     private DragStartState mDragStartState;
+    private boolean mIsReleased;
 
     public DesktopModeVisualIndicator(SyncTransactionQueue syncQueue,
             ActivityManager.RunningTaskInfo taskInfo, DisplayController displayController,
@@ -240,6 +241,7 @@
      * Create a fullscreen indicator with no animation
      */
     private void createView() {
+        if (mIsReleased) return;
         final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
         final Resources resources = mContext.getResources();
         final DisplayMetrics metrics = resources.getDisplayMetrics();
@@ -295,6 +297,12 @@
      * @param finishCallback called when animation ends or gets cancelled
      */
     void fadeOutIndicator(@Nullable Runnable finishCallback) {
+        if (mCurrentType == NO_INDICATOR) {
+            // In rare cases, fade out can be requested before the indicator has determined its
+            // initial type and started animating in. In this case, no animator is needed.
+            finishCallback.run();
+            return;
+        }
         final VisualIndicatorAnimator animator = VisualIndicatorAnimator
                 .fadeBoundsOut(mView, mCurrentType,
                         mDisplayController.getDisplayLayout(mTaskInfo.displayId));
@@ -335,6 +343,7 @@
      * Release the indicator and its components when it is no longer needed.
      */
     public void releaseVisualIndicator(SurfaceControl.Transaction t) {
+        mIsReleased = true;
         if (mViewHost == null) return;
         if (mViewHost != null) {
             mViewHost.release();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
index 7fcb767..ca3dc2d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
@@ -16,7 +16,7 @@
 
 package com.android.wm.shell.desktopmode
 
-import android.content.Context
+import android.content.pm.UserInfo
 import android.graphics.Rect
 import android.graphics.Region
 import android.util.ArrayMap
@@ -30,11 +30,8 @@
 import androidx.core.util.valueIterator
 import com.android.internal.protolog.ProtoLog
 import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
-import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer
 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
 import com.android.wm.shell.shared.annotations.ShellMainThread
-import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
-import com.android.wm.shell.sysui.ShellInit
 import java.io.PrintWriter
 import java.util.concurrent.Executor
 import java.util.function.Consumer
@@ -43,13 +40,10 @@
 
 /** Tracks desktop data for Android Desktop Windowing. */
 class DesktopRepository (
-    private val context: Context,
-    shellInit: ShellInit,
     private val persistentRepository: DesktopPersistentRepository,
-    private val repositoryInitializer: DesktopRepositoryInitializer,
     @ShellMainThread private val mainCoroutineScope: CoroutineScope,
+    val userId: Int,
 ){
-
     /**
      * Task data tracked per desktop.
      *
@@ -117,16 +111,6 @@
             this[displayId] ?: DesktopTaskData().also { this[displayId] = it }
     }
 
-    init {
-        if (DesktopModeStatus.canEnterDesktopMode(context)) {
-            shellInit.addInitCallback(::initRepoFromPersistentStorage, this)
-        }
-    }
-
-    private fun initRepoFromPersistentStorage() {
-        repositoryInitializer.initialize(this)
-    }
-
     /** Adds [activeTasksListener] to be notified of updates to active tasks. */
     fun addActiveTaskListener(activeTasksListener: ActiveTasksListener) {
         activeTasksListeners.add(activeTasksListener)
@@ -276,6 +260,8 @@
      * the set of visible tasks on that display and notifies listeners.
      */
     fun updateTask(displayId: Int, taskId: Int, isVisible: Boolean) {
+        logD("updateTask taskId=%d, displayId=%d, isVisible=%b", taskId, displayId, isVisible)
+
         if (isVisible) {
             // If task is visible, remove it from any other display besides [displayId].
             removeVisibleTask(taskId, excludedDisplayId = displayId)
@@ -495,6 +481,7 @@
                     persistentRepository.addOrUpdateDesktop(
                         // Use display id as desktop id for now since only once desktop per display
                         // is supported.
+                        userId = userId,
                         desktopId = displayId,
                         visibleTasks = desktopTaskDataByDisplayIdCopy.visibleTasks,
                         minimizedTasks = desktopTaskDataByDisplayIdCopy.minimizedTasks,
@@ -529,6 +516,7 @@
             )
             pw.println("${innerPrefix}minimizedTasks=${data.minimizedTasks.toDumpString()}")
             pw.println("${innerPrefix}fullImmersiveTaskId=${data.fullImmersiveTaskId}")
+            pw.println("${innerPrefix}wallpaperActivityToken=${wallpaperActivityToken}")
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt
index 94ac2e6..80d8bfb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt
@@ -23,10 +23,12 @@
 
 /** Manages tasks handling specific to Android Desktop Mode. */
 class DesktopTaskChangeListener(
-    private val desktopRepository: DesktopRepository,
+  private val desktopUserRepositories: DesktopUserRepositories,
 ) : TaskChangeListener {
 
   override fun onTaskOpening(taskInfo: RunningTaskInfo) {
+    val desktopRepository: DesktopRepository =
+      desktopUserRepositories.getProfile(taskInfo.userId)
     if (!isFreeformTask(taskInfo) && desktopRepository.isActiveTask(taskInfo.taskId)) {
       desktopRepository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId)
       return
@@ -37,6 +39,8 @@
   }
 
   override fun onTaskChanging(taskInfo: RunningTaskInfo) {
+    val desktopRepository: DesktopRepository =
+      desktopUserRepositories.getProfile(taskInfo.userId)
     if (!desktopRepository.isActiveTask(taskInfo.taskId)) return
 
     // Case 1: Freeform task is changed in Desktop Mode.
@@ -61,6 +65,8 @@
   }
 
   override fun onTaskMovingToFront(taskInfo: RunningTaskInfo) {
+    val desktopRepository: DesktopRepository =
+      desktopUserRepositories.getProfile(taskInfo.userId)
     if (!desktopRepository.isActiveTask(taskInfo.taskId)) return
     if (!isFreeformTask(taskInfo)) {
       desktopRepository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId)
@@ -74,6 +80,8 @@
   }
 
   override fun onTaskClosing(taskInfo: RunningTaskInfo) {
+    val desktopRepository: DesktopRepository =
+      desktopUserRepositories.getProfile(taskInfo.userId)
     if (!desktopRepository.isActiveTask(taskInfo.taskId)) return
     // TODO: b/370038902 - Handle Activity#finishAndRemoveTask.
     if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue() ||
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 ccbc920..5cb94f8 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
@@ -84,6 +84,7 @@
 import com.android.wm.shell.common.SingleInstanceRemoteListener
 import com.android.wm.shell.common.SyncTransactionQueue
 import com.android.wm.shell.compatui.isTopActivityExemptFromDesktopWindowing
+import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction
 import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.DragStartState
 import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType
 import com.android.wm.shell.desktopmode.DesktopRepository.VisibleTasksListener
@@ -130,6 +131,7 @@
 import java.util.function.Consumer
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
+import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventEnum
 import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.Companion.DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS
 import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION
 import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler.FULLSCREEN_ANIMATION_DURATION
@@ -157,7 +159,7 @@
     private val toggleResizeDesktopTaskTransitionHandler: ToggleResizeDesktopTaskTransitionHandler,
     private val dragToDesktopTransitionHandler: DragToDesktopTransitionHandler,
     private val desktopImmersiveController: DesktopImmersiveController,
-    private val taskRepository: DesktopRepository,
+    private val userRepositories: DesktopUserRepositories,
     private val recentsTransitionHandler: RecentsTransitionHandler,
     private val multiInstanceHelper: MultiInstanceHelper,
     @ShellMainThread private val mainExecutor: ShellExecutor,
@@ -166,6 +168,7 @@
     private val interactionJankMonitor: InteractionJankMonitor,
     @ShellMainThread private val handler: Handler,
     private val desktopModeEventLogger: DesktopModeEventLogger,
+    private val desktopModeUiEventLogger: DesktopModeUiEventLogger,
     private val desktopTilingDecorViewModel: DesktopTilingDecorViewModel,
 ) :
     RemoteCallable<DesktopTasksController>,
@@ -174,6 +177,7 @@
     UserChangeListener {
 
     private val desktopMode: DesktopModeImpl
+    private var taskRepository: DesktopRepository
     private var visualIndicator: DesktopModeVisualIndicator? = null
     private var userId: Int
     private val desktopModeShellCommandHandler: DesktopModeShellCommandHandler =
@@ -226,6 +230,7 @@
             shellInit.addInitCallback({ onInit() }, this)
         }
         userId = ActivityManager.getCurrentUser()
+        taskRepository = userRepositories.getProfile(userId)
     }
 
     private fun onInit() {
@@ -786,31 +791,6 @@
         transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
     }
 
-    /** Moves a task in/out of full immersive state within the desktop. */
-    fun toggleDesktopTaskFullImmersiveState(taskInfo: RunningTaskInfo) {
-        if (taskRepository.isTaskInFullImmersiveState(taskInfo.taskId)) {
-            exitDesktopTaskFromFullImmersive(
-                taskInfo,
-                DesktopImmersiveController.ExitReason.USER_INTERACTION,
-            )
-        } else {
-            moveDesktopTaskToFullImmersive(taskInfo)
-        }
-    }
-
-    private fun moveDesktopTaskToFullImmersive(taskInfo: RunningTaskInfo) {
-        check(taskInfo.isFreeform) { "Task must already be in freeform" }
-        desktopImmersiveController.moveTaskToImmersive(taskInfo)
-    }
-
-    private fun exitDesktopTaskFromFullImmersive(
-        taskInfo: RunningTaskInfo,
-        reason: DesktopImmersiveController.ExitReason,
-    ) {
-        check(taskInfo.isFreeform) { "Task must already be in freeform" }
-        desktopImmersiveController.moveTaskToNonImmersive(taskInfo, reason)
-    }
-
     /**
      * Quick-resizes a desktop task, toggling between a fullscreen state (represented by the stable
      * bounds) and a free floating state (either the last saved bounds if available or the default
@@ -818,28 +798,23 @@
      */
     fun toggleDesktopTaskSize(
         taskInfo: RunningTaskInfo,
-        resizeTrigger: ResizeTrigger,
-        motionEvent: MotionEvent?,
+        interaction: ToggleTaskSizeInteraction
     ) {
         val currentTaskBounds = taskInfo.configuration.windowConfiguration.bounds
         desktopModeEventLogger.logTaskResizingStarted(
-            resizeTrigger,
-            DesktopModeEventLogger.getInputMethodFromMotionEvent(motionEvent),
+            interaction.resizeTrigger,
+            interaction.inputMethod,
             taskInfo,
             currentTaskBounds.width(),
             currentTaskBounds.height(),
             displayController
         )
-
         val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return
-
-        val stableBounds = Rect().apply { displayLayout.getStableBounds(this) }
         val destinationBounds = Rect()
-
-        val isMaximized = isTaskMaximized(taskInfo, stableBounds)
+        val isMaximized = interaction.direction == ToggleTaskSizeInteraction.Direction.RESTORE
         // If the task is currently maximized, we will toggle it not to be and vice versa. This is
         // helpful to eliminate the current task from logic to calculate taskbar corner rounding.
-        val willMaximize = !isMaximized
+        val willMaximize = interaction.direction == ToggleTaskSizeInteraction.Direction.MAXIMIZE
         if (isMaximized) {
             // The desktop task is at the maximized width and/or height of the stable bounds.
             // If the task's pre-maximize stable bounds were saved, toggle the task to those bounds.
@@ -876,10 +851,16 @@
 
         taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding)
         val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds)
+        interaction.uiEvent?.let { uiEvent ->
+            desktopModeUiEventLogger.log(taskInfo, uiEvent)
+        }
         desktopModeEventLogger.logTaskResizingEnded(
-            resizeTrigger, DesktopModeEventLogger.getInputMethodFromMotionEvent(motionEvent),
-            taskInfo, destinationBounds.width(),
-            destinationBounds.height(), displayController
+            interaction.resizeTrigger,
+            interaction.inputMethod,
+            taskInfo,
+            destinationBounds.width(),
+            destinationBounds.height(),
+            displayController,
         )
         toggleResizeDesktopTaskTransitionHandler.startTransition(wct)
     }
@@ -890,10 +871,7 @@
         currentDragBounds: Rect,
         motionEvent: MotionEvent
     ) {
-        val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return
-        val stableBounds = Rect()
-        displayLayout.getStableBounds(stableBounds)
-        if (isTaskMaximized(taskInfo, stableBounds)) {
+        if (isTaskMaximized(taskInfo, displayController)) {
             // Handle the case where we attempt to drag-to-maximize when already maximized: the task
             // position won't need to change but we want to animate the surface going back to the
             // maximized position.
@@ -909,7 +887,14 @@
             return
         }
 
-        toggleDesktopTaskSize(taskInfo, ResizeTrigger.DRAG_TO_TOP_RESIZE_TRIGGER, motionEvent)
+        toggleDesktopTaskSize(
+            taskInfo,
+            ToggleTaskSizeInteraction(
+                direction = ToggleTaskSizeInteraction.Direction.MAXIMIZE,
+                source = ToggleTaskSizeInteraction.Source.HEADER_DRAG_TO_TOP,
+                inputMethod = DesktopModeEventLogger.getInputMethodFromMotionEvent(motionEvent),
+            )
+        )
     }
 
     private fun getMaximizeBounds(taskInfo: RunningTaskInfo, stableBounds: Rect): Rect {
@@ -926,19 +911,6 @@
         }
     }
 
-    private fun isTaskMaximized(
-        taskInfo: RunningTaskInfo,
-        stableBounds: Rect
-    ): Boolean {
-        val currentTaskBounds = taskInfo.configuration.windowConfiguration.bounds
-
-        return if (taskInfo.isResizeable) {
-            isTaskBoundsEqual(currentTaskBounds, stableBounds)
-        } else {
-            isTaskWidthOrHeightEqual(currentTaskBounds, stableBounds)
-        }
-    }
-
     private fun isMaximizedToStableBoundsEdges(
         taskInfo: RunningTaskInfo,
         stableBounds: Rect
@@ -1269,7 +1241,7 @@
                 /* requestCode= */ 0,
                 intent,
                 PendingIntent.FLAG_IMMUTABLE,
-                /* bundle= */ null,
+                /* options= */ null,
                 userHandle
             )
         wct.sendPendingIntent(pendingIntent, intent, options.toBundle())
@@ -1754,8 +1726,7 @@
     /** Handle task closing by removing wallpaper activity if it's the last active task */
     private fun handleTaskClosing(task: RunningTaskInfo, transition: IBinder, requestType: Int): WindowContainerTransaction? {
         logV("handleTaskClosing")
-        if (!isDesktopModeShowing(task.displayId))
-            return null
+        if (!isDesktopModeShowing(task.displayId)) return null
 
         val wct = WindowContainerTransaction()
         performDesktopExitCleanupIfNeeded(task.taskId, wct)
@@ -1772,6 +1743,7 @@
                 )
             )
         }
+
         taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(
             doesAnyTaskRequireTaskbarRounding(
                 task.displayId,
@@ -2083,6 +2055,10 @@
                 if (DesktopModeStatus.shouldMaximizeWhenDragToTopEdge(context)) {
                     dragToMaximizeDesktopTask(taskInfo, taskSurface, currentDragBounds, motionEvent)
                 } else {
+                    desktopModeUiEventLogger.log(
+                        taskInfo,
+                        DesktopUiEventEnum.DESKTOP_WINDOW_APP_HEADER_DRAG_TO_FULL_SCREEN
+                    )
                     moveToFullscreenWithAnimation(
                         taskInfo,
                         position,
@@ -2091,6 +2067,10 @@
                 }
             }
             IndicatorType.TO_SPLIT_LEFT_INDICATOR -> {
+                desktopModeUiEventLogger.log(
+                    taskInfo,
+                    DesktopUiEventEnum.DESKTOP_WINDOW_APP_HEADER_DRAG_TO_TILE_TO_LEFT
+                )
                 handleSnapResizingTaskOnDrag(
                     taskInfo,
                     SnapPosition.LEFT,
@@ -2102,6 +2082,10 @@
                 )
             }
             IndicatorType.TO_SPLIT_RIGHT_INDICATOR -> {
+                desktopModeUiEventLogger.log(
+                    taskInfo,
+                    DesktopUiEventEnum.DESKTOP_WINDOW_APP_HEADER_DRAG_TO_TILE_TO_RIGHT
+                )
                 handleSnapResizingTaskOnDrag(
                     taskInfo,
                     SnapPosition.RIGHT,
@@ -2188,16 +2172,32 @@
                 // Start a new jank interaction for the drag release to desktop window animation.
                 interactionJankMonitor.begin(taskSurface, context, handler,
                     CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE, "to_desktop")
+                desktopModeUiEventLogger.log(
+                    taskInfo,
+                    DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_DESKTOP_MODE
+                )
                 finalizeDragToDesktop(taskInfo)
             }
             IndicatorType.NO_INDICATOR,
             IndicatorType.TO_FULLSCREEN_INDICATOR -> {
+                desktopModeUiEventLogger.log(
+                    taskInfo,
+                    DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_FULL_SCREEN
+                )
                 cancelDragToDesktop(taskInfo)
             }
             IndicatorType.TO_SPLIT_LEFT_INDICATOR -> {
+                desktopModeUiEventLogger.log(
+                    taskInfo,
+                    DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_SPLIT_SCREEN
+                )
                 requestSplit(taskInfo, leftOrTop = true)
             }
             IndicatorType.TO_SPLIT_RIGHT_INDICATOR -> {
+                desktopModeUiEventLogger.log(
+                    taskInfo,
+                    DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_SPLIT_SCREEN
+                )
                 requestSplit(taskInfo, leftOrTop = false)
             }
         }
@@ -2329,7 +2329,9 @@
 
     // TODO(b/366397912): Support full multi-user mode in Windowing.
     override fun onUserChanged(newUserId: Int, userContext: Context) {
+        logV("onUserChanged previousUserId=%d, newUserId=%d", userId, newUserId)
         userId = newUserId
+        taskRepository = userRepositories.getProfile(userId)
         desktopTilingDecorViewModel.onUserChange()
     }
 
@@ -2341,7 +2343,7 @@
         if (inImmersive && !requestingImmersive
             && !RecentsTransitionStateListener.isRunning(recentsTransitionState)) {
             // Exit immersive if the app is no longer requesting it.
-            exitDesktopTaskFromFullImmersive(
+            desktopImmersiveController.moveTaskToNonImmersive(
                 taskInfo,
                 DesktopImmersiveController.ExitReason.APP_NOT_IMMERSIVE
             )
@@ -2352,6 +2354,7 @@
         val innerPrefix = "$prefix  "
         pw.println("${prefix}DesktopTasksController")
         DesktopModeStatus.dump(pw, innerPrefix, context)
+        pw.println("${prefix}userId=$userId")
         taskRepository.dump(pw, innerPrefix)
     }
 
@@ -2380,6 +2383,7 @@
             displayId: Int,
             transitionSource: DesktopModeTransitionSource
         ) {
+            logV("moveFocusedTaskToDesktop")
             mainExecutor.execute {
                 this@DesktopTasksController.moveFocusedTaskToDesktop(displayId, transitionSource)
             }
@@ -2389,12 +2393,14 @@
             displayId: Int,
             transitionSource: DesktopModeTransitionSource
         ) {
+            logV("moveFocusedTaskToFullscreen")
             mainExecutor.execute {
                 this@DesktopTasksController.enterFullscreen(displayId, transitionSource)
             }
         }
 
         override fun moveFocusedTaskToStageSplit(displayId: Int, leftOrTop: Boolean) {
+            logV("moveFocusedTaskToStageSplit")
             mainExecutor.execute { this@DesktopTasksController.enterSplit(displayId, leftOrTop) }
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
index 77af627..62b200a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.desktopmode
 
+import android.app.ActivityManager
 import android.content.Context
 import android.os.Handler
 import android.os.IBinder
@@ -31,6 +32,7 @@
 import com.android.wm.shell.ShellTaskOrganizer
 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
 import com.android.wm.shell.shared.annotations.ShellMainThread
+import com.android.wm.shell.sysui.UserChangeListener;
 import com.android.wm.shell.transition.Transitions
 import com.android.wm.shell.transition.Transitions.TransitionObserver
 
@@ -43,7 +45,7 @@
  */
 class DesktopTasksLimiter (
         transitions: Transitions,
-        private val taskRepository: DesktopRepository,
+        private val desktopUserRepositories: DesktopUserRepositories,
         private val shellTaskOrganizer: ShellTaskOrganizer,
         private val maxTasksLimit: Int,
         private val interactionJankMonitor: InteractionJankMonitor,
@@ -54,12 +56,15 @@
     @VisibleForTesting
     val leftoverMinimizedTasksRemover = LeftoverMinimizedTasksRemover()
 
+    private var userId: Int
+
     init {
         require(maxTasksLimit > 0) {
             "DesktopTasksLimiter: maxTasksLimit should be greater than 0. Current value: $maxTasksLimit."
         }
         transitions.registerObserver(minimizeTransitionObserver)
-        taskRepository.addActiveTaskListener(leftoverMinimizedTasksRemover)
+        userId = ActivityManager.getCurrentUser()
+        desktopUserRepositories.current.addActiveTaskListener(leftoverMinimizedTasksRemover)
         logV("Starting limiter with a maximum of %d tasks", maxTasksLimit)
     }
 
@@ -84,6 +89,7 @@
             startTransaction: SurfaceControl.Transaction,
             finishTransaction: SurfaceControl.Transaction
         ) {
+            val taskRepository = desktopUserRepositories.current
             val taskToMinimize = pendingTransitionTokensAndTasks.remove(transition) ?: return
             if (!taskRepository.isActiveTask(taskToMinimize.taskId)) return
             if (!isTaskReadyForMinimize(info, taskToMinimize)) {
@@ -114,6 +120,7 @@
         ): Boolean {
             val taskChange = info.changes.find { change ->
                 change.taskInfo?.taskId == taskDetails.taskId }
+            val taskRepository = desktopUserRepositories.current
             if (taskChange == null) return !taskRepository.isVisibleTask(taskDetails.taskId)
             return taskChange.mode == TRANSIT_TO_BACK
         }
@@ -151,7 +158,8 @@
     }
 
     @VisibleForTesting
-    inner class LeftoverMinimizedTasksRemover : DesktopRepository.ActiveTasksListener {
+    inner class LeftoverMinimizedTasksRemover
+            : DesktopRepository.ActiveTasksListener, UserChangeListener {
         override fun onActiveTasksChanged(displayId: Int) {
             // If back navigation is enabled, we shouldn't remove the leftover tasks
             if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue()) return
@@ -161,6 +169,7 @@
         }
 
         fun removeLeftoverMinimizedTasks(displayId: Int, wct: WindowContainerTransaction) {
+            val taskRepository = desktopUserRepositories.current
             if (taskRepository.getExpandedTasksOrdered(displayId).isNotEmpty()) return
             val remainingMinimizedTasks = taskRepository.getMinimizedTasks(displayId)
             if (remainingMinimizedTasks.isEmpty()) return
@@ -173,6 +182,15 @@
                 }
             }
         }
+
+        override fun onUserChanged(newUserId: Int, userContext: Context) {
+            // Removes active task listener for the previous repository
+            desktopUserRepositories.getProfile(userId).removeActiveTasksListener(this);
+
+            // Sets active listener for the current repository.
+            userId = newUserId
+            desktopUserRepositories.getProfile(newUserId).addActiveTaskListener(this);
+        }
     }
 
     /**
@@ -183,6 +201,7 @@
      */
     private fun minimizeTask(displayId: Int, taskId: Int) {
         logV("Minimize taskId=%d, displayId=%d", taskId, displayId)
+        val taskRepository = desktopUserRepositories.current
         taskRepository.minimizeTask(displayId, taskId)
     }
 
@@ -196,7 +215,7 @@
             newFrontTaskId: Int,
     ): Int? {
         logV("addAndGetMinimizeTaskChanges, newFrontTask=%d", newFrontTaskId)
-
+        val taskRepository = desktopUserRepositories.current
         val taskIdToMinimize =
             getTaskIdToMinimize(
                 taskRepository.getExpandedTasksOrdered(displayId),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
index c39c715..d6bb7f9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.desktopmode
 
+import android.app.ActivityManager
 import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
 import android.content.Context
 import android.os.IBinder
@@ -43,7 +44,7 @@
  */
 class DesktopTasksTransitionObserver(
     private val context: Context,
-    private val desktopRepository: DesktopRepository,
+    private val desktopUserRepositories: DesktopUserRepositories,
     private val transitions: Transitions,
     private val shellTaskOrganizer: ShellTaskOrganizer,
     private val desktopMixedTransitionHandler: DesktopMixedTransitionHandler,
@@ -51,11 +52,13 @@
 ) : Transitions.TransitionObserver {
 
     private var transitionToCloseWallpaper: IBinder? = null
+    private var currentProfileId: Int
 
     init {
         if (DesktopModeStatus.canEnterDesktopMode(context)) {
             shellInit.addInitCallback(::onInit, this)
         }
+        currentProfileId = ActivityManager.getCurrentUser()
     }
 
     fun onInit() {
@@ -89,6 +92,7 @@
             val taskInfo = change.taskInfo
             if (taskInfo == null || taskInfo.taskId == -1) continue
 
+            val desktopRepository = desktopUserRepositories.getProfile(taskInfo.userId)
             if (desktopRepository.isActiveTask(taskInfo.taskId) &&
                 taskInfo.windowingMode != WINDOWING_MODE_FREEFORM) {
                 desktopRepository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId)
@@ -105,7 +109,7 @@
                 if (taskInfo == null || taskInfo.taskId == -1) {
                     continue
                 }
-
+                val desktopRepository = desktopUserRepositories.getProfile(taskInfo.userId)
                 val visibleTaskCount = desktopRepository.getVisibleTaskCount(taskInfo.displayId)
                 if (visibleTaskCount > 0 &&
                     change.mode == TRANSIT_TO_BACK &&
@@ -128,12 +132,13 @@
             if (taskInfo == null || taskInfo.taskId == -1) {
                 continue
             }
-
+            val desktopRepository = desktopUserRepositories.getProfile(taskInfo.userId)
             if (desktopRepository.getVisibleTaskCount(taskInfo.displayId) == 1 &&
                 change.mode == TRANSIT_CLOSE &&
                 taskInfo.windowingMode == WINDOWING_MODE_FREEFORM &&
                 desktopRepository.wallpaperActivityToken != null) {
                 transitionToCloseWallpaper = transition
+                currentProfileId = taskInfo.userId
             }
         }
     }
@@ -150,6 +155,7 @@
         // TODO: b/332682201 Update repository state
         if (transitionToCloseWallpaper == transition) {
             // TODO: b/362469671 - Handle merging the animation when desktop is also closing.
+            val desktopRepository = desktopUserRepositories.getProfile(currentProfileId)
             desktopRepository.wallpaperActivityToken?.let { wallpaperActivityToken ->
                 transitions.startTransition(
                     TRANSIT_CLOSE,
@@ -167,6 +173,7 @@
         info.changes.forEach { change ->
             change.taskInfo?.let { taskInfo ->
                 if (DesktopWallpaperActivity.isWallpaperTask(taskInfo)) {
+                    val desktopRepository = desktopUserRepositories.getProfile(taskInfo.userId)
                     when (change.mode) {
                         WindowManager.TRANSIT_OPEN -> {
                             desktopRepository.wallpaperActivityToken = taskInfo.token
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopUserRepositories.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopUserRepositories.kt
new file mode 100644
index 0000000..1e5a1b2
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopUserRepositories.kt
@@ -0,0 +1,109 @@
+/*
+ * 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.desktopmode
+
+import android.app.ActivityManager
+import android.content.Context
+import android.content.pm.UserInfo
+import android.os.UserManager
+import android.util.SparseArray
+import com.android.window.flags.Flags
+import com.android.internal.protolog.ProtoLog
+import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
+import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
+import com.android.wm.shell.shared.annotations.ShellMainThread
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import com.android.wm.shell.sysui.ShellInit
+import com.android.wm.shell.sysui.UserChangeListener
+import kotlinx.coroutines.CoroutineScope
+
+/** Manages per-user DesktopRepository instances. */
+class DesktopUserRepositories(
+    context: Context,
+    shellInit: ShellInit,
+    private val persistentRepository: DesktopPersistentRepository,
+    private val repositoryInitializer: DesktopRepositoryInitializer,
+    @ShellMainThread private val mainCoroutineScope: CoroutineScope,
+    userManager: UserManager,
+) : UserChangeListener {
+    private var userId: Int
+    private var userIdToProfileIdsMap: MutableMap<Int, List<Int>> = mutableMapOf()
+
+    // TODO(b/357060209): Add caching for this logic to improve efficiency.
+    val current: DesktopRepository
+        get() = desktopRepoByUserId.getOrCreate(userId)
+
+    private val desktopRepoByUserId =
+        object : SparseArray<DesktopRepository>() {
+            /** Gets [DesktopRepository] for existing [userId] or creates a new one. */
+            fun getOrCreate(userId: Int): DesktopRepository =
+                this[userId]
+                    ?: DesktopRepository(
+                        persistentRepository,
+                        mainCoroutineScope,
+                        userId)
+                        .also { this[userId] = it }
+        }
+
+    init {
+        userId = ActivityManager.getCurrentUser()
+        if (DesktopModeStatus.canEnterDesktopMode(context)) {
+            shellInit.addInitCallback(::initRepoFromPersistentStorage, this)
+        }
+        if (Flags.enableDesktopWindowingHsum()) {
+            userIdToProfileIdsMap[userId] = userManager.getProfiles(userId).map { it.id }
+        }
+    }
+
+    private fun initRepoFromPersistentStorage() {
+        repositoryInitializer.initialize(this)
+    }
+
+    /** Returns [DesktopRepository] for the parent user id. */
+    fun getProfile(profileId: Int): DesktopRepository {
+        if (Flags.enableDesktopWindowingHsum()) {
+            for ((uid, profileIds) in userIdToProfileIdsMap) {
+                if (profileId in profileIds) {
+                    return desktopRepoByUserId.getOrCreate(uid)
+                }
+            }
+        }
+        return desktopRepoByUserId.getOrCreate(profileId)
+    }
+
+    override fun onUserChanged(newUserId: Int, userContext: Context) {
+        logD("onUserChanged previousUserId=%d, newUserId=%d", userId, newUserId)
+        userId = newUserId
+    }
+
+    override fun onUserProfilesChanged(profiles: MutableList<UserInfo>) {
+        logD("onUserProfilesChanged profiles=%s", profiles.toString())
+        if (Flags.enableDesktopWindowingHsum()) {
+            // TODO(b/366397912): Remove all persisted profile data when the profile changes.
+            userIdToProfileIdsMap[userId] = profiles.map { it.id }
+        }
+    }
+
+    private fun logD(msg: String, vararg arguments: Any?) {
+        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
+    }
+
+    companion object {
+        private const val TAG = "DesktopUserRepositories"
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopWallpaperActivity.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopWallpaperActivity.kt
index e835b2f..909a066 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopWallpaperActivity.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopWallpaperActivity.kt
@@ -17,12 +17,10 @@
 package com.android.wm.shell.desktopmode
 
 import android.app.Activity
-import android.app.ActivityManager
+import android.app.TaskInfo
 import android.content.ComponentName
 import android.os.Bundle
 import android.view.WindowManager
-import com.android.internal.protolog.ProtoLog
-import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
 
 /**
  * A transparent activity used in the desktop mode to show the wallpaper under the freeform windows.
@@ -42,11 +40,12 @@
 
     companion object {
         private const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui"
-        private val wallpaperActivityComponent =
+        @JvmStatic
+        val wallpaperActivityComponent =
             ComponentName(SYSTEM_UI_PACKAGE_NAME, DesktopWallpaperActivity::class.java.name)
 
         @JvmStatic
-        fun isWallpaperTask(taskInfo: ActivityManager.RunningTaskInfo) =
+        fun isWallpaperTask(taskInfo: TaskInfo) =
             taskInfo.baseIntent.component?.let(::isWallpaperComponent) ?: false
 
         @JvmStatic
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt
index 9411150..6df3302 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt
@@ -119,6 +119,7 @@
                             initialBounds = null
                             boundsAnimator = null
                             interactionJankMonitor.end(Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW)
+                            interactionJankMonitor.end(Cuj.CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW)
                             interactionJankMonitor.end(Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE)
                         }
                     )
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/common/ToggleTaskSizeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/common/ToggleTaskSizeUtils.kt
new file mode 100644
index 0000000..7afd8d7
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/common/ToggleTaskSizeUtils.kt
@@ -0,0 +1,149 @@
+/*
+ * 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.desktopmode.common
+
+import com.android.internal.jank.Cuj
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
+import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventEnum
+import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction.AmbiguousSource
+import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction.Source
+
+/** Represents a user interaction to toggle a desktop task's size from to maximize or vice versa. */
+data class ToggleTaskSizeInteraction(
+    val direction: Direction,
+    val source: Source,
+    val inputMethod: InputMethod,
+) {
+    constructor(
+        isMaximized: Boolean,
+        source: Source,
+        inputMethod: InputMethod,
+    ) : this(
+        direction = if (isMaximized) Direction.RESTORE else Direction.MAXIMIZE,
+        source = source,
+        inputMethod = inputMethod,
+    )
+
+    val jankTag: String? =
+        when (source) {
+            Source.HEADER_BUTTON_TO_MAXIMIZE -> "caption_bar_button"
+            Source.HEADER_BUTTON_TO_RESTORE -> "caption_bar_button"
+            Source.KEYBOARD_SHORTCUT -> null
+            Source.HEADER_DRAG_TO_TOP -> null
+            Source.MAXIMIZE_MENU_TO_MAXIMIZE -> "maximize_menu"
+            Source.MAXIMIZE_MENU_TO_RESTORE -> "maximize_menu"
+            Source.DOUBLE_TAP_TO_MAXIMIZE -> "double_tap"
+            Source.DOUBLE_TAP_TO_RESTORE -> "double_tap"
+        }
+    val uiEvent: DesktopUiEventEnum? =
+        when (source) {
+            Source.HEADER_BUTTON_TO_MAXIMIZE ->
+                DesktopUiEventEnum.DESKTOP_WINDOW_MAXIMIZE_BUTTON_TAP
+            Source.HEADER_BUTTON_TO_RESTORE -> DesktopUiEventEnum.DESKTOP_WINDOW_RESTORE_BUTTON_TAP
+            Source.KEYBOARD_SHORTCUT -> null
+            Source.HEADER_DRAG_TO_TOP -> null
+            Source.MAXIMIZE_MENU_TO_MAXIMIZE -> {
+                DesktopUiEventEnum.DESKTOP_WINDOW_MAXIMIZE_BUTTON_MENU_TAP_TO_MAXIMIZE
+            }
+            Source.MAXIMIZE_MENU_TO_RESTORE -> {
+                DesktopUiEventEnum.DESKTOP_WINDOW_MAXIMIZE_BUTTON_MENU_TAP_TO_RESTORE
+            }
+            Source.DOUBLE_TAP_TO_MAXIMIZE -> {
+                DesktopUiEventEnum.DESKTOP_WINDOW_HEADER_DOUBLE_TAP_TO_MAXIMIZE
+            }
+            Source.DOUBLE_TAP_TO_RESTORE -> {
+                DesktopUiEventEnum.DESKTOP_WINDOW_HEADER_DOUBLE_TAP_TO_RESTORE
+            }
+        }
+    val resizeTrigger =
+        when (source) {
+            Source.HEADER_BUTTON_TO_MAXIMIZE -> ResizeTrigger.MAXIMIZE_BUTTON
+            Source.HEADER_BUTTON_TO_RESTORE -> ResizeTrigger.MAXIMIZE_BUTTON
+            Source.KEYBOARD_SHORTCUT -> ResizeTrigger.UNKNOWN_RESIZE_TRIGGER
+            Source.HEADER_DRAG_TO_TOP -> ResizeTrigger.DRAG_TO_TOP_RESIZE_TRIGGER
+            Source.MAXIMIZE_MENU_TO_MAXIMIZE -> ResizeTrigger.MAXIMIZE_MENU
+            Source.MAXIMIZE_MENU_TO_RESTORE -> ResizeTrigger.MAXIMIZE_MENU
+            Source.DOUBLE_TAP_TO_MAXIMIZE -> ResizeTrigger.DOUBLE_TAP_APP_HEADER
+            Source.DOUBLE_TAP_TO_RESTORE -> ResizeTrigger.DOUBLE_TAP_APP_HEADER
+        }
+    val cujTracing: Int? =
+        when (source) {
+            Source.HEADER_BUTTON_TO_MAXIMIZE -> Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW
+            Source.HEADER_BUTTON_TO_RESTORE -> Cuj.CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW
+            Source.KEYBOARD_SHORTCUT -> null
+            Source.HEADER_DRAG_TO_TOP -> null
+            Source.MAXIMIZE_MENU_TO_MAXIMIZE -> null
+            Source.MAXIMIZE_MENU_TO_RESTORE -> null
+            Source.DOUBLE_TAP_TO_MAXIMIZE -> null
+            Source.DOUBLE_TAP_TO_RESTORE -> null
+        }
+
+    /** The direction to which the task is being resized. */
+    enum class Direction {
+        MAXIMIZE,
+        RESTORE,
+    }
+
+    /** The user interaction source. */
+    enum class Source {
+        HEADER_BUTTON_TO_MAXIMIZE,
+        HEADER_BUTTON_TO_RESTORE,
+        KEYBOARD_SHORTCUT,
+        HEADER_DRAG_TO_TOP,
+        MAXIMIZE_MENU_TO_MAXIMIZE,
+        MAXIMIZE_MENU_TO_RESTORE,
+        DOUBLE_TAP_TO_MAXIMIZE,
+        DOUBLE_TAP_TO_RESTORE,
+    }
+
+    /**
+     * Temporary sources for interactions that should be broken into more specific sources, for
+     * example, the header button click should use [Source.HEADER_BUTTON_TO_MAXIMIZE] and
+     * [Source.HEADER_BUTTON_TO_RESTORE].
+     *
+     * TODO: b/341320112 - break these out into different [Source]s.
+     */
+    enum class AmbiguousSource {
+        HEADER_BUTTON,
+        MAXIMIZE_MENU,
+        DOUBLE_TAP,
+    }
+}
+
+/** Returns the non-ambiguous [Source] based on the maximized state of the task. */
+fun AmbiguousSource.toSource(isMaximized: Boolean): Source {
+    return when (this) {
+        AmbiguousSource.HEADER_BUTTON ->
+            if (isMaximized) {
+                Source.HEADER_BUTTON_TO_RESTORE
+            } else {
+                Source.HEADER_BUTTON_TO_MAXIMIZE
+            }
+        AmbiguousSource.MAXIMIZE_MENU ->
+            if (isMaximized) {
+                Source.MAXIMIZE_MENU_TO_RESTORE
+            } else {
+                Source.MAXIMIZE_MENU_TO_MAXIMIZE
+            }
+        AmbiguousSource.DOUBLE_TAP ->
+            if (isMaximized) {
+                Source.DOUBLE_TAP_TO_RESTORE
+            } else {
+                Source.DOUBLE_TAP_TO_MAXIMIZE
+            }
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandler.kt
index 826de08..a428ce1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandler.kt
@@ -29,7 +29,7 @@
 import com.android.internal.protolog.ProtoLog
 import com.android.wm.shell.common.ShellExecutor
 import com.android.wm.shell.compatui.isTopActivityExemptFromDesktopWindowing
-import com.android.wm.shell.desktopmode.DesktopRepository
+import com.android.wm.shell.desktopmode.DesktopUserRepositories
 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
 import com.android.wm.shell.shared.TransitionUtil.isClosingMode
 import com.android.wm.shell.shared.TransitionUtil.isClosingType
@@ -46,7 +46,7 @@
     private val animExecutor: ShellExecutor,
     private val shellInit: ShellInit,
     private val transitions: Transitions,
-    private val desktopRepository: DesktopRepository,
+    private val desktopUserRepositories: DesktopUserRepositories,
 ) : TransitionHandler {
 
     private val showingSystemModalsIds = mutableSetOf<Int>()
@@ -156,7 +156,7 @@
         }
 
     private fun isDesktopModeShowing(displayId: Int): Boolean =
-        desktopRepository.getVisibleTaskCount(displayId) > 0
+        desktopUserRepositories.current.getVisibleTaskCount(displayId) > 0
 
     override fun handleRequest(
         transition: IBinder,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt
index e01c448..c5fca02 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt
@@ -36,8 +36,8 @@
 import com.android.wm.shell.windowdecor.common.DecorThemeUtil
 import com.android.wm.shell.windowdecor.common.Theme
 import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationTooltipController
-import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationTooltipController.TooltipEducationViewConfig
 import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationTooltipController.TooltipColorScheme
+import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationTooltipController.TooltipEducationViewConfig
 import kotlin.time.Duration.Companion.milliseconds
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.MainCoroutineDispatcher
@@ -74,293 +74,330 @@
     @ShellMainThread private val applicationCoroutineScope: CoroutineScope,
     @ShellBackgroundThread private val backgroundDispatcher: MainCoroutineDispatcher,
 ) {
-  private val decorThemeUtil = DecorThemeUtil(context)
-  private lateinit var openHandleMenuCallback: (Int) -> Unit
-  private lateinit var toDesktopModeCallback: (Int, DesktopModeTransitionSource) -> Unit
+    private val decorThemeUtil = DecorThemeUtil(context)
+    private lateinit var openHandleMenuCallback: (Int) -> Unit
+    private lateinit var toDesktopModeCallback: (Int, DesktopModeTransitionSource) -> Unit
 
-  init {
-    runIfEducationFeatureEnabled {
-      applicationCoroutineScope.launch {
-        // Central block handling the app handle's educational flow end-to-end.
-        isEducationViewedFlow()
-            .flatMapLatest { isEducationViewed ->
-              if (isEducationViewed) {
-                // If the education is viewed then return emptyFlow() that completes immediately.
-                // This will help us to not listen to [captionHandleStateFlow] after the education
-                // has been viewed already.
-                emptyFlow()
-              } else {
-                // Listen for changes to window decor's caption handle.
-                windowDecorCaptionHandleRepository.captionStateFlow
-                    // Wait for few seconds before emitting the latest state.
-                    .debounce(APP_HANDLE_EDUCATION_DELAY_MILLIS)
-                    .filter { captionState ->
-                      captionState is CaptionState.AppHandle &&
-                          appHandleEducationFilter.shouldShowAppHandleEducation(captionState)
+    init {
+        runIfEducationFeatureEnabled {
+            applicationCoroutineScope.launch {
+                // Central block handling the app handle's educational flow end-to-end.
+                isAppHandleHintViewedFlow()
+                    .flatMapLatest { isAppHandleHintViewed ->
+                        if (isAppHandleHintViewed) {
+                            // If the education is viewed then return emptyFlow() that completes
+                            // immediately.
+                            // This will help us to not listen to [captionHandleStateFlow] after the
+                            // education
+                            // has been viewed already.
+                            emptyFlow()
+                        } else {
+                            // Listen for changes to window decor's caption handle.
+                            windowDecorCaptionHandleRepository.captionStateFlow
+                                // Wait for few seconds before emitting the latest state.
+                                .debounce(APP_HANDLE_EDUCATION_DELAY_MILLIS)
+                                .filter { captionState ->
+                                    captionState is CaptionState.AppHandle &&
+                                        appHandleEducationFilter.shouldShowAppHandleEducation(
+                                            captionState
+                                        )
+                                }
+                        }
                     }
-              }
-            }
-            .flowOn(backgroundDispatcher)
-            .collectLatest { captionState ->
-              val tooltipColorScheme = tooltipColorScheme(captionState)
+                    .flowOn(backgroundDispatcher)
+                    .collectLatest { captionState ->
+                        val tooltipColorScheme = tooltipColorScheme(captionState)
 
-              showEducation(captionState, tooltipColorScheme)
-              // After showing first tooltip, mark education as viewed
-              appHandleEducationDatastoreRepository.updateEducationViewedTimestampMillis(true)
+                        showEducation(captionState, tooltipColorScheme)
+                        // After showing first tooltip, mark education as viewed
+                        appHandleEducationDatastoreRepository
+                            .updateAppHandleHintViewedTimestampMillis(true)
+                    }
             }
-      }
 
-      applicationCoroutineScope.launch {
-        if (isFeatureUsed()) return@launch
+            applicationCoroutineScope.launch {
+                if (isAppHandleHintUsed()) return@launch
+                windowDecorCaptionHandleRepository.captionStateFlow
+                    .filter { captionState ->
+                        captionState is CaptionState.AppHandle && captionState.isHandleMenuExpanded
+                    }
+                    .take(1)
+                    .flowOn(backgroundDispatcher)
+                    .collect {
+                        // If user expands app handle, mark user has used the app handle hint
+                        appHandleEducationDatastoreRepository
+                            .updateAppHandleHintUsedTimestampMillis(true)
+                    }
+            }
+        }
+    }
+
+    private inline fun runIfEducationFeatureEnabled(block: () -> Unit) {
+        if (canEnterDesktopMode(context) && Flags.enableDesktopWindowingAppHandleEducation())
+            block()
+    }
+
+    private fun showEducation(captionState: CaptionState, tooltipColorScheme: TooltipColorScheme) {
+        val appHandleBounds = (captionState as CaptionState.AppHandle).globalAppHandleBounds
+        val tooltipGlobalCoordinates =
+            Point(appHandleBounds.left + appHandleBounds.width() / 2, appHandleBounds.bottom)
+        // TODO: b/370546801 - Differentiate between user dismissing the tooltip vs following the
+        // cue.
+        // Populate information important to inflate app handle education tooltip.
+        val appHandleTooltipConfig =
+            TooltipEducationViewConfig(
+                tooltipViewLayout = R.layout.desktop_windowing_education_top_arrow_tooltip,
+                tooltipColorScheme = tooltipColorScheme,
+                tooltipViewGlobalCoordinates = tooltipGlobalCoordinates,
+                tooltipText = getString(R.string.windowing_app_handle_education_tooltip),
+                arrowDirection =
+                    DesktopWindowingEducationTooltipController.TooltipArrowDirection.UP,
+                onEducationClickAction = {
+                    launchWithExceptionHandling {
+                        showWindowingImageButtonTooltip(tooltipColorScheme)
+                    }
+                    openHandleMenuCallback(captionState.runningTaskInfo.taskId)
+                },
+                onDismissAction = {
+                    launchWithExceptionHandling {
+                        showWindowingImageButtonTooltip(tooltipColorScheme)
+                    }
+                },
+            )
+
+        windowingEducationViewController.showEducationTooltip(
+            tooltipViewConfig = appHandleTooltipConfig,
+            taskId = captionState.runningTaskInfo.taskId,
+        )
+    }
+
+    /** Show tooltip that points to windowing image button in app handle menu */
+    private suspend fun showWindowingImageButtonTooltip(tooltipColorScheme: TooltipColorScheme) {
+        val appInfoPillHeight = getSize(R.dimen.desktop_mode_handle_menu_app_info_pill_height)
+        val windowingOptionPillHeight =
+            getSize(R.dimen.desktop_mode_handle_menu_windowing_pill_height)
+        val appHandleMenuWidth =
+            getSize(R.dimen.desktop_mode_handle_menu_width) +
+                getSize(R.dimen.desktop_mode_handle_menu_pill_spacing_margin)
+        val appHandleMenuMargins =
+            getSize(R.dimen.desktop_mode_handle_menu_margin_top) +
+                getSize(R.dimen.desktop_mode_handle_menu_pill_spacing_margin)
+
         windowDecorCaptionHandleRepository.captionStateFlow
-            .filter { captionState ->
-              captionState is CaptionState.AppHandle && captionState.isHandleMenuExpanded
+            // After the first tooltip was dismissed, wait for 400 ms and see if the app handle menu
+            // has been expanded.
+            .timeout(APP_HANDLE_EDUCATION_TIMEOUT_MILLIS.milliseconds)
+            .catchTimeoutAndLog {
+                // TODO: b/341320146 - Log previous tooltip was dismissed
             }
+            // Wait for few milliseconds before emitting the latest state.
+            .debounce(APP_HANDLE_EDUCATION_DELAY_MILLIS)
+            .filter { captionState ->
+                // Filter out states when app handle is not visible or not expanded.
+                captionState is CaptionState.AppHandle && captionState.isHandleMenuExpanded
+            }
+            // Before showing this tooltip, stop listening to further emissions to avoid
+            // accidentally
+            // showing the same tooltip on future emissions.
             .take(1)
             .flowOn(backgroundDispatcher)
-            .collect {
-              // If user expands app handle, mark user has used the feature
-              appHandleEducationDatastoreRepository.updateFeatureUsedTimestampMillis(true)
+            .collectLatest { captionState ->
+                captionState as CaptionState.AppHandle
+                val appHandleBounds = captionState.globalAppHandleBounds
+                val tooltipGlobalCoordinates =
+                    Point(
+                        appHandleBounds.left + appHandleBounds.width() / 2 + appHandleMenuWidth / 2,
+                        appHandleBounds.top +
+                            appHandleMenuMargins +
+                            appInfoPillHeight +
+                            windowingOptionPillHeight / 2,
+                    )
+                // Populate information important to inflate windowing image button education
+                // tooltip.
+                val windowingImageButtonTooltipConfig =
+                    TooltipEducationViewConfig(
+                        tooltipViewLayout = R.layout.desktop_windowing_education_left_arrow_tooltip,
+                        tooltipColorScheme = tooltipColorScheme,
+                        tooltipViewGlobalCoordinates = tooltipGlobalCoordinates,
+                        tooltipText =
+                            getString(
+                                R.string.windowing_desktop_mode_image_button_education_tooltip
+                            ),
+                        arrowDirection =
+                            DesktopWindowingEducationTooltipController.TooltipArrowDirection.LEFT,
+                        onEducationClickAction = {
+                            launchWithExceptionHandling {
+                                showExitWindowingTooltip(tooltipColorScheme)
+                            }
+                            toDesktopModeCallback(
+                                captionState.runningTaskInfo.taskId,
+                                DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON,
+                            )
+                        },
+                        onDismissAction = {
+                            launchWithExceptionHandling {
+                                showExitWindowingTooltip(tooltipColorScheme)
+                            }
+                        },
+                    )
+
+                windowingEducationViewController.showEducationTooltip(
+                    taskId = captionState.runningTaskInfo.taskId,
+                    tooltipViewConfig = windowingImageButtonTooltipConfig,
+                )
             }
-      }
     }
-  }
 
-  private inline fun runIfEducationFeatureEnabled(block: () -> Unit) {
-    if (canEnterDesktopMode(context) && Flags.enableDesktopWindowingAppHandleEducation()) block()
-  }
+    /** Show tooltip that points to app chip button and educates user on how to exit desktop mode */
+    private suspend fun showExitWindowingTooltip(tooltipColorScheme: TooltipColorScheme) {
+        windowDecorCaptionHandleRepository.captionStateFlow
+            // After the previous tooltip was dismissed, wait for 400 ms and see if the user entered
+            // desktop mode.
+            .timeout(APP_HANDLE_EDUCATION_TIMEOUT_MILLIS.milliseconds)
+            .catchTimeoutAndLog {
+                // TODO: b/341320146 - Log previous tooltip was dismissed
+            }
+            // Wait for few milliseconds before emitting the latest state.
+            .debounce(APP_HANDLE_EDUCATION_DELAY_MILLIS)
+            .filter { captionState ->
+                // Filter out states when app header is not visible or expanded.
+                captionState is CaptionState.AppHeader && !captionState.isHeaderMenuExpanded
+            }
+            // Before showing this tooltip, stop listening to further emissions to avoid
+            // accidentally
+            // showing the same tooltip on future emissions.
+            .take(1)
+            .flowOn(backgroundDispatcher)
+            .collectLatest { captionState ->
+                captionState as CaptionState.AppHeader
+                val globalAppChipBounds = captionState.globalAppChipBounds
+                val tooltipGlobalCoordinates =
+                    Point(
+                        globalAppChipBounds.right,
+                        globalAppChipBounds.top + globalAppChipBounds.height() / 2,
+                    )
+                // Populate information important to inflate exit desktop mode education tooltip.
+                val exitWindowingTooltipConfig =
+                    TooltipEducationViewConfig(
+                        tooltipViewLayout = R.layout.desktop_windowing_education_left_arrow_tooltip,
+                        tooltipColorScheme = tooltipColorScheme,
+                        tooltipViewGlobalCoordinates = tooltipGlobalCoordinates,
+                        tooltipText =
+                            getString(R.string.windowing_desktop_mode_exit_education_tooltip),
+                        arrowDirection =
+                            DesktopWindowingEducationTooltipController.TooltipArrowDirection.LEFT,
+                        onDismissAction = {},
+                        onEducationClickAction = {
+                            openHandleMenuCallback(captionState.runningTaskInfo.taskId)
+                        },
+                    )
+                windowingEducationViewController.showEducationTooltip(
+                    taskId = captionState.runningTaskInfo.taskId,
+                    tooltipViewConfig = exitWindowingTooltipConfig,
+                )
+            }
+    }
 
-  private fun showEducation(captionState: CaptionState, tooltipColorScheme: TooltipColorScheme) {
-    val appHandleBounds = (captionState as CaptionState.AppHandle).globalAppHandleBounds
-    val tooltipGlobalCoordinates =
-        Point(appHandleBounds.left + appHandleBounds.width() / 2, appHandleBounds.bottom)
-    // TODO: b/370546801 - Differentiate between user dismissing the tooltip vs following the cue.
-    // Populate information important to inflate app handle education tooltip.
-    val appHandleTooltipConfig =
-        TooltipEducationViewConfig(
-            tooltipViewLayout = R.layout.desktop_windowing_education_top_arrow_tooltip,
-            tooltipColorScheme = tooltipColorScheme,
-            tooltipViewGlobalCoordinates = tooltipGlobalCoordinates,
-            tooltipText = getString(R.string.windowing_app_handle_education_tooltip),
-            arrowDirection = DesktopWindowingEducationTooltipController.TooltipArrowDirection.UP,
-            onEducationClickAction = {
-              launchWithExceptionHandling { showWindowingImageButtonTooltip(tooltipColorScheme) }
-              openHandleMenuCallback(captionState.runningTaskInfo.taskId)
-            },
-            onDismissAction = {
-              launchWithExceptionHandling { showWindowingImageButtonTooltip(tooltipColorScheme) }
-            },
-        )
+    private fun tooltipColorScheme(captionState: CaptionState): TooltipColorScheme {
+        context.withStyledAttributes(
+            set = null,
+            attrs =
+                intArrayOf(
+                    com.android.internal.R.attr.materialColorOnTertiaryFixed,
+                    com.android.internal.R.attr.materialColorTertiaryFixed,
+                    com.android.internal.R.attr.materialColorTertiaryFixedDim,
+                ),
+            defStyleAttr = 0,
+            defStyleRes = 0,
+        ) {
+            val onTertiaryFixed = getColor(/* index= */ 0, /* defValue= */ 0)
+            val tertiaryFixed = getColor(/* index= */ 1, /* defValue= */ 0)
+            val tertiaryFixedDim = getColor(/* index= */ 2, /* defValue= */ 0)
+            val taskInfo = (captionState as CaptionState.AppHandle).runningTaskInfo
 
-    windowingEducationViewController.showEducationTooltip(
-        tooltipViewConfig = appHandleTooltipConfig, taskId = captionState.runningTaskInfo.taskId)
-  }
-
-  /** Show tooltip that points to windowing image button in app handle menu */
-  private suspend fun showWindowingImageButtonTooltip(tooltipColorScheme: TooltipColorScheme) {
-    val appInfoPillHeight = getSize(R.dimen.desktop_mode_handle_menu_app_info_pill_height)
-    val windowingOptionPillHeight = getSize(R.dimen.desktop_mode_handle_menu_windowing_pill_height)
-    val appHandleMenuWidth =
-        getSize(R.dimen.desktop_mode_handle_menu_width) +
-            getSize(R.dimen.desktop_mode_handle_menu_pill_spacing_margin)
-    val appHandleMenuMargins =
-        getSize(R.dimen.desktop_mode_handle_menu_margin_top) +
-            getSize(R.dimen.desktop_mode_handle_menu_pill_spacing_margin)
-
-    windowDecorCaptionHandleRepository.captionStateFlow
-        // After the first tooltip was dismissed, wait for 400 ms and see if the app handle menu
-        // has been expanded.
-        .timeout(APP_HANDLE_EDUCATION_TIMEOUT_MILLIS.milliseconds)
-        .catchTimeoutAndLog {
-          // TODO: b/341320146 - Log previous tooltip was dismissed
+            val tooltipContainerColor =
+                if (decorThemeUtil.getAppTheme(taskInfo) == Theme.LIGHT) {
+                    tertiaryFixed
+                } else {
+                    tertiaryFixedDim
+                }
+            return TooltipColorScheme(tooltipContainerColor, onTertiaryFixed, onTertiaryFixed)
         }
-        // Wait for few milliseconds before emitting the latest state.
-        .debounce(APP_HANDLE_EDUCATION_DELAY_MILLIS)
-        .filter { captionState ->
-          // Filter out states when app handle is not visible or not expanded.
-          captionState is CaptionState.AppHandle && captionState.isHandleMenuExpanded
+        return TooltipColorScheme(0, 0, 0)
+    }
+
+    /**
+     * Setup callbacks for app handle education tooltips.
+     *
+     * @param openHandleMenuCallback callback invoked to open app handle menu or app chip menu.
+     * @param toDesktopModeCallback callback invoked to move task into desktop mode.
+     */
+    fun setAppHandleEducationTooltipCallbacks(
+        openHandleMenuCallback: (taskId: Int) -> Unit,
+        toDesktopModeCallback: (taskId: Int, DesktopModeTransitionSource) -> Unit,
+    ) {
+        this.openHandleMenuCallback = openHandleMenuCallback
+        this.toDesktopModeCallback = toDesktopModeCallback
+    }
+
+    private inline fun <T> Flow<T>.catchTimeoutAndLog(crossinline block: () -> Unit) =
+        catch { exception ->
+            if (exception is TimeoutCancellationException) block() else throw exception
         }
-        // Before showing this tooltip, stop listening to further emissions to avoid accidentally
-        // showing the same tooltip on future emissions.
-        .take(1)
-        .flowOn(backgroundDispatcher)
-        .collectLatest { captionState ->
-          captionState as CaptionState.AppHandle
-          val appHandleBounds = captionState.globalAppHandleBounds
-          val tooltipGlobalCoordinates =
-              Point(
-                  appHandleBounds.left + appHandleBounds.width() / 2 + appHandleMenuWidth / 2,
-                  appHandleBounds.top +
-                      appHandleMenuMargins +
-                      appInfoPillHeight +
-                      windowingOptionPillHeight / 2)
-          // Populate information important to inflate windowing image button education tooltip.
-          val windowingImageButtonTooltipConfig =
-              TooltipEducationViewConfig(
-                  tooltipViewLayout = R.layout.desktop_windowing_education_left_arrow_tooltip,
-                  tooltipColorScheme = tooltipColorScheme,
-                  tooltipViewGlobalCoordinates = tooltipGlobalCoordinates,
-                  tooltipText =
-                      getString(R.string.windowing_desktop_mode_image_button_education_tooltip),
-                  arrowDirection =
-                      DesktopWindowingEducationTooltipController.TooltipArrowDirection.LEFT,
-                  onEducationClickAction = {
-                    launchWithExceptionHandling { showExitWindowingTooltip(tooltipColorScheme) }
-                    toDesktopModeCallback(
-                        captionState.runningTaskInfo.taskId,
-                        DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON)
-                  },
-                  onDismissAction = {
-                    launchWithExceptionHandling { showExitWindowingTooltip(tooltipColorScheme) }
-                  },
-              )
 
-          windowingEducationViewController.showEducationTooltip(
-              taskId = captionState.runningTaskInfo.taskId,
-              tooltipViewConfig = windowingImageButtonTooltipConfig)
+    private fun launchWithExceptionHandling(block: suspend () -> Unit) =
+        applicationCoroutineScope.launch {
+            try {
+                block()
+            } catch (e: Throwable) {
+                Slog.e(TAG, "Error: ", e)
+            }
         }
-  }
 
-  /** Show tooltip that points to app chip button and educates user on how to exit desktop mode */
-  private suspend fun showExitWindowingTooltip(tooltipColorScheme: TooltipColorScheme) {
-    windowDecorCaptionHandleRepository.captionStateFlow
-        // After the previous tooltip was dismissed, wait for 400 ms and see if the user entered
-        // desktop mode.
-        .timeout(APP_HANDLE_EDUCATION_TIMEOUT_MILLIS.milliseconds)
-        .catchTimeoutAndLog {
-          // TODO: b/341320146 - Log previous tooltip was dismissed
-        }
-        // Wait for few milliseconds before emitting the latest state.
-        .debounce(APP_HANDLE_EDUCATION_DELAY_MILLIS)
-        .filter { captionState ->
-          // Filter out states when app header is not visible or expanded.
-          captionState is CaptionState.AppHeader && !captionState.isHeaderMenuExpanded
-        }
-        // Before showing this tooltip, stop listening to further emissions to avoid accidentally
-        // showing the same tooltip on future emissions.
-        .take(1)
-        .flowOn(backgroundDispatcher)
-        .collectLatest { captionState ->
-          captionState as CaptionState.AppHeader
-          val globalAppChipBounds = captionState.globalAppChipBounds
-          val tooltipGlobalCoordinates =
-              Point(
-                  globalAppChipBounds.right,
-                  globalAppChipBounds.top + globalAppChipBounds.height() / 2)
-          // Populate information important to inflate exit desktop mode education tooltip.
-          val exitWindowingTooltipConfig =
-              TooltipEducationViewConfig(
-                  tooltipViewLayout = R.layout.desktop_windowing_education_left_arrow_tooltip,
-                  tooltipColorScheme = tooltipColorScheme,
-                  tooltipViewGlobalCoordinates = tooltipGlobalCoordinates,
-                  tooltipText = getString(R.string.windowing_desktop_mode_exit_education_tooltip),
-                  arrowDirection =
-                      DesktopWindowingEducationTooltipController.TooltipArrowDirection.LEFT,
-                  onDismissAction = {},
-                  onEducationClickAction = {
-                    openHandleMenuCallback(captionState.runningTaskInfo.taskId)
-                  },
-              )
-          windowingEducationViewController.showEducationTooltip(
-              taskId = captionState.runningTaskInfo.taskId,
-              tooltipViewConfig = exitWindowingTooltipConfig,
-          )
-        }
-  }
+    /**
+     * Listens to the changes to [WindowingEducationProto#hasAppHandleHintViewedTimestampMillis()]
+     * in datastore proto object.
+     *
+     * If [SHOULD_OVERRIDE_EDUCATION_CONDITIONS] is true, this flow will always emit false. That
+     * means it will always emit app handle hint has not been viewed yet.
+     */
+    private fun isAppHandleHintViewedFlow(): Flow<Boolean> =
+        appHandleEducationDatastoreRepository.dataStoreFlow
+            .map { preferences ->
+                preferences.hasAppHandleHintViewedTimestampMillis() &&
+                    !SHOULD_OVERRIDE_EDUCATION_CONDITIONS
+            }
+            .distinctUntilChanged()
 
-  private fun tooltipColorScheme(captionState: CaptionState): TooltipColorScheme {
-    context.withStyledAttributes(
-        set = null,
-        attrs =
-            intArrayOf(
-                com.android.internal.R.attr.materialColorOnTertiaryFixed,
-                com.android.internal.R.attr.materialColorTertiaryFixed,
-                com.android.internal.R.attr.materialColorTertiaryFixedDim),
-        defStyleAttr = 0,
-        defStyleRes = 0) {
-          val onTertiaryFixed = getColor(/* index= */ 0, /* defValue= */ 0)
-          val tertiaryFixed = getColor(/* index= */ 1, /* defValue= */ 0)
-          val tertiaryFixedDim = getColor(/* index= */ 2, /* defValue= */ 0)
-          val taskInfo = (captionState as CaptionState.AppHandle).runningTaskInfo
+    /**
+     * Listens to the changes to [WindowingEducationProto#hasAppHandleHintUsedTimestampMillis()] in
+     * datastore proto object.
+     */
+    private suspend fun isAppHandleHintUsed(): Boolean =
+        appHandleEducationDatastoreRepository.dataStoreFlow
+            .first()
+            .hasAppHandleHintUsedTimestampMillis()
 
-          val tooltipContainerColor =
-              if (decorThemeUtil.getAppTheme(taskInfo) == Theme.LIGHT) {
-                tertiaryFixed
-              } else {
-                tertiaryFixedDim
-              }
-          return TooltipColorScheme(tooltipContainerColor, onTertiaryFixed, onTertiaryFixed)
-        }
-    return TooltipColorScheme(0, 0, 0)
-  }
+    private fun getSize(@DimenRes resourceId: Int): Int {
+        if (resourceId == Resources.ID_NULL) return 0
+        return context.resources.getDimensionPixelSize(resourceId)
+    }
 
-  /**
-   * Setup callbacks for app handle education tooltips.
-   *
-   * @param openHandleMenuCallback callback invoked to open app handle menu or app chip menu.
-   * @param toDesktopModeCallback callback invoked to move task into desktop mode.
-   */
-  fun setAppHandleEducationTooltipCallbacks(
-      openHandleMenuCallback: (taskId: Int) -> Unit,
-      toDesktopModeCallback: (taskId: Int, DesktopModeTransitionSource) -> Unit
-  ) {
-    this.openHandleMenuCallback = openHandleMenuCallback
-    this.toDesktopModeCallback = toDesktopModeCallback
-  }
+    private fun getString(@StringRes resId: Int): String = context.resources.getString(resId)
 
-  private inline fun <T> Flow<T>.catchTimeoutAndLog(crossinline block: () -> Unit) =
-      catch { exception ->
-        if (exception is TimeoutCancellationException) block() else throw exception
-      }
+    companion object {
+        const val TAG = "AppHandleEducationController"
+        val APP_HANDLE_EDUCATION_DELAY_MILLIS: Long
+            get() = SystemProperties.getLong("persist.windowing_app_handle_education_delay", 3000L)
 
-  private fun launchWithExceptionHandling(block: suspend () -> Unit) =
-      applicationCoroutineScope.launch {
-        try {
-          block()
-        } catch (e: Throwable) {
-          Slog.e(TAG, "Error: ", e)
-        }
-      }
+        val APP_HANDLE_EDUCATION_TIMEOUT_MILLIS: Long
+            get() = SystemProperties.getLong("persist.windowing_app_handle_education_timeout", 400L)
 
-  /**
-   * Listens to the changes to [WindowingEducationProto#hasEducationViewedTimestampMillis()] in
-   * datastore proto object.
-   *
-   * If [SHOULD_OVERRIDE_EDUCATION_CONDITIONS] is true, this flow will always emit false. That means
-   * it will emit education has not been viewed yet always.
-   */
-  private fun isEducationViewedFlow(): Flow<Boolean> =
-      appHandleEducationDatastoreRepository.dataStoreFlow
-          .map { preferences ->
-            preferences.hasEducationViewedTimestampMillis() && !SHOULD_OVERRIDE_EDUCATION_CONDITIONS
-          }
-          .distinctUntilChanged()
-
-  /**
-   * Listens to the changes to [WindowingEducationProto#hasFeatureUsedTimestampMillis()] in
-   * datastore proto object.
-   */
-  private suspend fun isFeatureUsed(): Boolean =
-      appHandleEducationDatastoreRepository.dataStoreFlow.first().hasFeatureUsedTimestampMillis()
-
-  private fun getSize(@DimenRes resourceId: Int): Int {
-    if (resourceId == Resources.ID_NULL) return 0
-    return context.resources.getDimensionPixelSize(resourceId)
-  }
-
-  private fun getString(@StringRes resId: Int): String = context.resources.getString(resId)
-
-  companion object {
-    const val TAG = "AppHandleEducationController"
-    val APP_HANDLE_EDUCATION_DELAY_MILLIS: Long
-      get() = SystemProperties.getLong("persist.windowing_app_handle_education_delay", 3000L)
-
-    val APP_HANDLE_EDUCATION_TIMEOUT_MILLIS: Long
-      get() = SystemProperties.getLong("persist.windowing_app_handle_education_timeout", 400L)
-
-    val SHOULD_OVERRIDE_EDUCATION_CONDITIONS: Boolean
-      get() =
-          SystemProperties.getBoolean(
-              "persist.desktop_windowing_app_handle_education_override_conditions", false)
-  }
+        val SHOULD_OVERRIDE_EDUCATION_CONDITIONS: Boolean
+            get() =
+                SystemProperties.getBoolean(
+                    "persist.desktop_windowing_app_handle_education_override_conditions",
+                    false,
+                )
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilter.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilter.kt
index 144370d..9990846 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilter.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilter.kt
@@ -32,106 +32,114 @@
 /** Filters incoming app handle education triggers based on set conditions. */
 class AppHandleEducationFilter(
     private val context: Context,
-    private val appHandleEducationDatastoreRepository: AppHandleEducationDatastoreRepository
+    private val appHandleEducationDatastoreRepository: AppHandleEducationDatastoreRepository,
 ) {
-  private val usageStatsManager =
-      context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
+    private val usageStatsManager =
+        context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
 
-  /**
-   * Returns true if conditions to show app handle education are met, returns false otherwise.
-   *
-   * If [SHOULD_OVERRIDE_EDUCATION_CONDITIONS] is true, this method will always return
-   * ![captionState.isHandleMenuExpanded].
-   */
-  suspend fun shouldShowAppHandleEducation(captionState: CaptionState): Boolean {
-    if ((captionState as CaptionState.AppHandle).isHandleMenuExpanded) return false
-    if (SHOULD_OVERRIDE_EDUCATION_CONDITIONS) return true
+    /**
+     * Returns true if conditions to show app handle education are met, returns false otherwise.
+     *
+     * If [SHOULD_OVERRIDE_EDUCATION_CONDITIONS] is true, this method will always return
+     * ![captionState.isHandleMenuExpanded].
+     */
+    suspend fun shouldShowAppHandleEducation(captionState: CaptionState): Boolean {
+        if ((captionState as CaptionState.AppHandle).isHandleMenuExpanded) return false
+        if (SHOULD_OVERRIDE_EDUCATION_CONDITIONS) return true
 
-    val focusAppPackageName =
-        captionState.runningTaskInfo.topActivityInfo?.packageName ?: return false
-    val windowingEducationProto = appHandleEducationDatastoreRepository.windowingEducationProto()
+        val focusAppPackageName =
+            captionState.runningTaskInfo.topActivityInfo?.packageName ?: return false
+        val windowingEducationProto =
+            appHandleEducationDatastoreRepository.windowingEducationProto()
 
-    return isFocusAppInAllowlist(focusAppPackageName) &&
-        !isOtherEducationShowing() &&
-        hasSufficientTimeSinceSetup() &&
-        !isEducationViewedBefore(windowingEducationProto) &&
-        !isFeatureUsedBefore(windowingEducationProto) &&
-        hasMinAppUsage(windowingEducationProto, focusAppPackageName)
-  }
+        return isFocusAppInAllowlist(focusAppPackageName) &&
+            !isOtherEducationShowing() &&
+            hasSufficientTimeSinceSetup() &&
+            !isAppHandleHintViewedBefore(windowingEducationProto) &&
+            !isAppHandleHintUsedBefore(windowingEducationProto) &&
+            hasMinAppUsage(windowingEducationProto, focusAppPackageName)
+    }
 
-  private fun isFocusAppInAllowlist(focusAppPackageName: String): Boolean =
-      focusAppPackageName in
-          context.resources.getStringArray(
-              R.array.desktop_windowing_app_handle_education_allowlist_apps)
+    private fun isFocusAppInAllowlist(focusAppPackageName: String): Boolean =
+        focusAppPackageName in
+            context.resources.getStringArray(
+                R.array.desktop_windowing_app_handle_education_allowlist_apps
+            )
 
-  // TODO: b/350953004 - Add checks based on App compat
-  // TODO: b/350951797 - Add checks based on PKT tips education
-  private fun isOtherEducationShowing(): Boolean = isTaskbarEducationShowing()
+    // TODO: b/350953004 - Add checks based on App compat
+    // TODO: b/350951797 - Add checks based on PKT tips education
+    private fun isOtherEducationShowing(): Boolean = isTaskbarEducationShowing()
 
-  private fun isTaskbarEducationShowing(): Boolean =
-      Secure.getInt(context.contentResolver, Secure.LAUNCHER_TASKBAR_EDUCATION_SHOWING, 0) == 1
+    private fun isTaskbarEducationShowing(): Boolean =
+        Secure.getInt(context.contentResolver, Secure.LAUNCHER_TASKBAR_EDUCATION_SHOWING, 0) == 1
 
-  private fun hasSufficientTimeSinceSetup(): Boolean =
-      Duration.ofMillis(SystemClock.elapsedRealtime()) >
-          convertIntegerResourceToDuration(
-              R.integer.desktop_windowing_education_required_time_since_setup_seconds)
+    private fun hasSufficientTimeSinceSetup(): Boolean =
+        Duration.ofMillis(SystemClock.elapsedRealtime()) >
+            convertIntegerResourceToDuration(
+                R.integer.desktop_windowing_education_required_time_since_setup_seconds
+            )
 
-  private fun isEducationViewedBefore(windowingEducationProto: WindowingEducationProto): Boolean =
-      windowingEducationProto.hasEducationViewedTimestampMillis()
+    private fun isAppHandleHintViewedBefore(
+        windowingEducationProto: WindowingEducationProto
+    ): Boolean = windowingEducationProto.hasAppHandleHintViewedTimestampMillis()
 
-  private fun isFeatureUsedBefore(windowingEducationProto: WindowingEducationProto): Boolean =
-      windowingEducationProto.hasFeatureUsedTimestampMillis()
+    private fun isAppHandleHintUsedBefore(
+        windowingEducationProto: WindowingEducationProto
+    ): Boolean = windowingEducationProto.hasAppHandleHintUsedTimestampMillis()
 
-  private suspend fun hasMinAppUsage(
-      windowingEducationProto: WindowingEducationProto,
-      focusAppPackageName: String
-  ): Boolean =
-      (launchCountByPackageName(windowingEducationProto)[focusAppPackageName] ?: 0) >=
-          context.resources.getInteger(R.integer.desktop_windowing_education_min_app_launch_count)
+    private suspend fun hasMinAppUsage(
+        windowingEducationProto: WindowingEducationProto,
+        focusAppPackageName: String,
+    ): Boolean =
+        (launchCountByPackageName(windowingEducationProto)[focusAppPackageName] ?: 0) >=
+            context.resources.getInteger(R.integer.desktop_windowing_education_min_app_launch_count)
 
-  private suspend fun launchCountByPackageName(
-      windowingEducationProto: WindowingEducationProto
-  ): Map<String, Int> =
-      if (isAppUsageCacheStale(windowingEducationProto)) {
-        // Query and return user stats, update cache in datastore
-        getAndCacheAppUsageStats()
-      } else {
-        // Return cached usage stats
-        windowingEducationProto.appHandleEducation.appUsageStatsMap
-      }
+    private suspend fun launchCountByPackageName(
+        windowingEducationProto: WindowingEducationProto
+    ): Map<String, Int> =
+        if (isAppUsageCacheStale(windowingEducationProto)) {
+            // Query and return user stats, update cache in datastore
+            getAndCacheAppUsageStats()
+        } else {
+            // Return cached usage stats
+            windowingEducationProto.appHandleEducation.appUsageStatsMap
+        }
 
-  private fun isAppUsageCacheStale(windowingEducationProto: WindowingEducationProto): Boolean {
-    val currentTime = currentTimeInDuration()
-    val lastUpdateTime =
-        Duration.ofMillis(
-            windowingEducationProto.appHandleEducation.appUsageStatsLastUpdateTimestampMillis)
-    val appUsageStatsCachingInterval =
-        convertIntegerResourceToDuration(
-            R.integer.desktop_windowing_education_app_usage_cache_interval_seconds)
-    return (currentTime - lastUpdateTime) > appUsageStatsCachingInterval
-  }
+    private fun isAppUsageCacheStale(windowingEducationProto: WindowingEducationProto): Boolean {
+        val currentTime = currentTimeInDuration()
+        val lastUpdateTime =
+            Duration.ofMillis(
+                windowingEducationProto.appHandleEducation.appUsageStatsLastUpdateTimestampMillis
+            )
+        val appUsageStatsCachingInterval =
+            convertIntegerResourceToDuration(
+                R.integer.desktop_windowing_education_app_usage_cache_interval_seconds
+            )
+        return (currentTime - lastUpdateTime) > appUsageStatsCachingInterval
+    }
 
-  private suspend fun getAndCacheAppUsageStats(): Map<String, Int> {
-    val currentTime = currentTimeInDuration()
-    val appUsageStats = queryAppUsageStats()
-    appHandleEducationDatastoreRepository.updateAppUsageStats(appUsageStats, currentTime)
-    return appUsageStats
-  }
+    private suspend fun getAndCacheAppUsageStats(): Map<String, Int> {
+        val currentTime = currentTimeInDuration()
+        val appUsageStats = queryAppUsageStats()
+        appHandleEducationDatastoreRepository.updateAppUsageStats(appUsageStats, currentTime)
+        return appUsageStats
+    }
 
-  private fun queryAppUsageStats(): Map<String, Int> {
-    val endTime = currentTimeInDuration()
-    val appLaunchInterval =
-        convertIntegerResourceToDuration(
-            R.integer.desktop_windowing_education_app_launch_interval_seconds)
-    val startTime = endTime - appLaunchInterval
+    private fun queryAppUsageStats(): Map<String, Int> {
+        val endTime = currentTimeInDuration()
+        val appLaunchInterval =
+            convertIntegerResourceToDuration(
+                R.integer.desktop_windowing_education_app_launch_interval_seconds
+            )
+        val startTime = endTime - appLaunchInterval
 
-    return usageStatsManager
-        .queryAndAggregateUsageStats(startTime.toMillis(), endTime.toMillis())
-        .mapValues { it.value.appLaunchCount }
-  }
+        return usageStatsManager
+            .queryAndAggregateUsageStats(startTime.toMillis(), endTime.toMillis())
+            .mapValues { it.value.appLaunchCount }
+    }
 
-  private fun convertIntegerResourceToDuration(@IntegerRes resourceId: Int): Duration =
-      Duration.ofSeconds(context.resources.getInteger(resourceId).toLong())
+    private fun convertIntegerResourceToDuration(@IntegerRes resourceId: Int): Duration =
+        Duration.ofSeconds(context.resources.getInteger(resourceId).toLong())
 
-  private fun currentTimeInDuration(): Duration = Duration.ofMillis(System.currentTimeMillis())
+    private fun currentTimeInDuration(): Duration = Duration.ofMillis(System.currentTimeMillis())
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppToWebEducationController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppToWebEducationController.kt
index 693da81..ac0a627 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppToWebEducationController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppToWebEducationController.kt
@@ -53,8 +53,8 @@
 /**
  * Controls App-to-Web education end to end.
  *
- * Listen to usages of App-to-Web, calls an api to check if the education
- * should be shown and controls education UI.
+ * Listen to usages of App-to-Web, calls an api to check if the education should be shown and
+ * controls education UI.
  */
 @OptIn(kotlinx.coroutines.FlowPreview::class)
 @kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -88,8 +88,9 @@
                                 .debounce(APP_TO_WEB_EDUCATION_DELAY_MILLIS)
                                 .filter { captionState ->
                                     captionState !is CaptionState.NoCaption &&
-                                            appToWebEducationFilter
-                                                .shouldShowAppToWebEducation(captionState)
+                                        appToWebEducationFilter.shouldShowAppToWebEducation(
+                                            captionState
+                                        )
                                 }
                         }
                     }
@@ -104,18 +105,23 @@
 
             applicationCoroutineScope.launch {
                 if (isFeatureUsed()) return@launch
-                windowDecorCaptionHandleRepository.appToWebUsageFlow
-                    .collect {
-                        // If user utilizes App-to-Web, mark user has used the feature
-                        appToWebEducationDatastoreRepository
-                            .updateFeatureUsedTimestampMillis(isViewed = true)
-                    }
+                windowDecorCaptionHandleRepository.appToWebUsageFlow.collect {
+                    // If user utilizes App-to-Web, mark user has used the feature
+                    appToWebEducationDatastoreRepository.updateFeatureUsedTimestampMillis(
+                        isViewed = true
+                    )
+                }
             }
         }
     }
 
     private inline fun runIfEducationFeatureEnabled(block: () -> Unit) {
-        if (canEnterDesktopMode(context) && Flags.enableDesktopWindowingAppToWebEducation()) block()
+        if (
+            canEnterDesktopMode(context) &&
+                Flags.enableDesktopWindowingAppToWebEducationIntegration()
+        ) {
+            block()
+        }
     }
 
     private fun showEducation(captionState: CaptionState, colorScheme: EducationColorScheme) {
@@ -126,10 +132,8 @@
                 val appHandleBounds = captionState.globalAppHandleBounds
                 val educationWidth =
                     loadDimensionPixelSize(R.dimen.desktop_windowing_education_promo_width)
-                educationGlobalCoordinates = Point(
-                    appHandleBounds.centerX() - educationWidth / 2,
-                    appHandleBounds.bottom
-                )
+                educationGlobalCoordinates =
+                    Point(appHandleBounds.centerX() - educationWidth / 2, appHandleBounds.bottom)
                 taskId = captionState.runningTaskInfo.taskId
             }
 
@@ -152,19 +156,22 @@
                 viewGlobalCoordinates = educationGlobalCoordinates,
                 educationText = getString(R.string.desktop_windowing_app_to_web_education_text),
                 widthId = R.dimen.desktop_windowing_education_promo_width,
-                heightId = R.dimen.desktop_windowing_education_promo_height
+                heightId = R.dimen.desktop_windowing_education_promo_height,
             )
 
         windowingEducationViewController.showEducation(
-            viewConfig = educationConfig, taskId = taskId)
+            viewConfig = educationConfig,
+            taskId = taskId,
+        )
     }
 
     private fun educationColorScheme(captionState: CaptionState): EducationColorScheme? {
-        val taskInfo: RunningTaskInfo = when (captionState) {
-            is CaptionState.AppHandle -> captionState.runningTaskInfo
-            is CaptionState.AppHeader -> captionState.runningTaskInfo
-            else -> return null
-        }
+        val taskInfo: RunningTaskInfo =
+            when (captionState) {
+                is CaptionState.AppHandle -> captionState.runningTaskInfo
+                is CaptionState.AppHeader -> captionState.runningTaskInfo
+                else -> return null
+            }
 
         val colorScheme = decorThemeUtil.getColorScheme(taskInfo)
         val tooltipContainerColor = colorScheme.surfaceBright.toArgb()
@@ -178,8 +185,7 @@
      */
     private fun isEducationViewLimitReachedFlow(): Flow<Boolean> =
         appToWebEducationDatastoreRepository.dataStoreFlow
-            .map { preferences ->
-                appToWebEducationFilter.isEducationViewLimitReached(preferences)}
+            .map { preferences -> appToWebEducationFilter.isEducationViewLimitReached(preferences) }
             .distinctUntilChanged()
 
     /**
@@ -199,9 +205,6 @@
     companion object {
         const val TAG = "AppToWebEducationController"
         val APP_TO_WEB_EDUCATION_DELAY_MILLIS: Long
-            get() = SystemProperties.getLong(
-                "persist.windowing_app_handle_education_delay",
-                3000L
-            )
+            get() = SystemProperties.getLong("persist.windowing_app_handle_education_delay", 3000L)
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppToWebEducationFilter.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppToWebEducationFilter.kt
index feee6ed..e272b54 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppToWebEducationFilter.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppToWebEducationFilter.kt
@@ -30,39 +30,41 @@
 /** Filters incoming App-to-Web education triggers based on set conditions. */
 class AppToWebEducationFilter(
     private val context: Context,
-    private val appToWebEducationDatastoreRepository: AppToWebEducationDatastoreRepository
+    private val appToWebEducationDatastoreRepository: AppToWebEducationDatastoreRepository,
 ) {
 
     /** Returns true if conditions to show App-to-web education are met, returns false otherwise. */
     suspend fun shouldShowAppToWebEducation(captionState: CaptionState): Boolean {
-        val (taskInfo: RunningTaskInfo, isCapturedLinkAvailable: Boolean) = when (captionState) {
-            is CaptionState.AppHandle ->
-                Pair(captionState.runningTaskInfo, captionState.isCapturedLinkAvailable)
-            is CaptionState.AppHeader ->
-                Pair(captionState.runningTaskInfo, captionState.isCapturedLinkAvailable)
-            else -> return false
-        }
+        val (taskInfo: RunningTaskInfo, isCapturedLinkAvailable: Boolean) =
+            when (captionState) {
+                is CaptionState.AppHandle ->
+                    Pair(captionState.runningTaskInfo, captionState.isCapturedLinkAvailable)
+                is CaptionState.AppHeader ->
+                    Pair(captionState.runningTaskInfo, captionState.isCapturedLinkAvailable)
+                else -> return false
+            }
 
         val focusAppPackageName = taskInfo.topActivityInfo?.packageName ?: return false
         val windowingEducationProto = appToWebEducationDatastoreRepository.windowingEducationProto()
 
         return !isOtherEducationShowing() &&
-                !isEducationViewLimitReached(windowingEducationProto) &&
-                hasSufficientTimeSinceSetup() &&
-                !isFeatureUsedBefore(windowingEducationProto) &&
-                isCapturedLinkAvailable &&
-                isFocusAppInAllowlist(focusAppPackageName)
+            !isEducationViewLimitReached(windowingEducationProto) &&
+            hasSufficientTimeSinceSetup() &&
+            !isFeatureUsedBefore(windowingEducationProto) &&
+            isCapturedLinkAvailable &&
+            isFocusAppInAllowlist(focusAppPackageName)
     }
 
     private fun isFocusAppInAllowlist(focusAppPackageName: String): Boolean =
         focusAppPackageName in
-                context.resources.getStringArray(
-                    R.array.desktop_windowing_app_to_web_education_allowlist_apps)
+            context.resources.getStringArray(
+                R.array.desktop_windowing_app_to_web_education_allowlist_apps
+            )
 
     // TODO: b/350953004 - Add checks based on App compat
     // TODO: b/350951797 - Add checks based on PKT tips education
-    private fun isOtherEducationShowing(): Boolean = isTaskbarEducationShowing() ||
-            isCompatUiEducationShowing()
+    private fun isOtherEducationShowing(): Boolean =
+        isTaskbarEducationShowing() || isCompatUiEducationShowing()
 
     private fun isTaskbarEducationShowing(): Boolean =
         Secure.getInt(context.contentResolver, Secure.LAUNCHER_TASKBAR_EDUCATION_SHOWING, 0) == 1
@@ -72,13 +74,14 @@
 
     private fun hasSufficientTimeSinceSetup(): Boolean =
         Duration.ofMillis(SystemClock.elapsedRealtime()) >
-                convertIntegerResourceToDuration(
-                    R.integer.desktop_windowing_education_required_time_since_setup_seconds)
+            convertIntegerResourceToDuration(
+                R.integer.desktop_windowing_education_required_time_since_setup_seconds
+            )
 
     /** Returns true if education is viewed maximum amount of times it should be shown. */
     fun isEducationViewLimitReached(windowingEducationProto: WindowingEducationProto): Boolean =
         windowingEducationProto.getAppToWebEducation().getEducationShownCount() >=
-                MAXIMUM_TIMES_EDUCATION_SHOWN
+            MAXIMUM_TIMES_EDUCATION_SHOWN
 
     private fun isFeatureUsedBefore(windowingEducationProto: WindowingEducationProto): Boolean =
         windowingEducationProto.hasFeatureUsedTimestampMillis()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppHandleEducationDatastoreRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppHandleEducationDatastoreRepository.kt
index d21b208..3e120b0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppHandleEducationDatastoreRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppHandleEducationDatastoreRepository.kt
@@ -42,101 +42,109 @@
 class AppHandleEducationDatastoreRepository
 @VisibleForTesting
 constructor(private val dataStore: DataStore<WindowingEducationProto>) {
-  constructor(
-      context: Context
-  ) : this(
-      DataStoreFactory.create(
-          serializer = WindowingEducationProtoSerializer,
-          produceFile = { context.dataStoreFile(APP_HANDLE_EDUCATION_DATASTORE_FILEPATH) }))
+    constructor(
+        context: Context
+    ) : this(
+        DataStoreFactory.create(
+            serializer = WindowingEducationProtoSerializer,
+            produceFile = { context.dataStoreFile(APP_HANDLE_EDUCATION_DATASTORE_FILEPATH) },
+        )
+    )
 
-  /** Provides dataStore.data flow and handles exceptions thrown during collection */
-  val dataStoreFlow: Flow<WindowingEducationProto> =
-      dataStore.data.catch { exception ->
-        // dataStore.data throws an IOException when an error is encountered when reading data
-        if (exception is IOException) {
-          Log.e(
-              TAG,
-              "Error in reading app handle education related data from datastore, data is " +
-                  "stored in a file named $APP_HANDLE_EDUCATION_DATASTORE_FILEPATH",
-              exception)
-        } else {
-          throw exception
+    /** Provides dataStore.data flow and handles exceptions thrown during collection */
+    val dataStoreFlow: Flow<WindowingEducationProto> =
+        dataStore.data.catch { exception ->
+            // dataStore.data throws an IOException when an error is encountered when reading data
+            if (exception is IOException) {
+                Log.e(
+                    TAG,
+                    "Error in reading app handle education related data from datastore, data is " +
+                        "stored in a file named $APP_HANDLE_EDUCATION_DATASTORE_FILEPATH",
+                    exception,
+                )
+            } else {
+                throw exception
+            }
         }
-      }
 
-  /**
-   * Reads and returns the [WindowingEducationProto] Proto object from the DataStore. If the
-   * DataStore is empty or there's an error reading, it returns the default value of Proto.
-   */
-  suspend fun windowingEducationProto(): WindowingEducationProto = dataStoreFlow.first()
+    /**
+     * Reads and returns the [WindowingEducationProto] Proto object from the DataStore. If the
+     * DataStore is empty or there's an error reading, it returns the default value of Proto.
+     */
+    suspend fun windowingEducationProto(): WindowingEducationProto = dataStoreFlow.first()
 
-  /**
-   * Updates [WindowingEducationProto.educationViewedTimestampMillis_] field in datastore with
-   * current timestamp if [isViewed] is true, if not then clears the field.
-   */
-  suspend fun updateEducationViewedTimestampMillis(isViewed: Boolean) {
-    dataStore.updateData { preferences ->
-      if (isViewed) {
-        preferences
-            .toBuilder()
-            .setEducationViewedTimestampMillis(System.currentTimeMillis())
-            .build()
-      } else {
-        preferences.toBuilder().clearEducationViewedTimestampMillis().build()
-      }
+    /**
+     * Updates [WindowingEducationProto.appHandleHintViewedTimestampMillis_] field in datastore with
+     * current timestamp if [isViewed] is true, if not then clears the field.
+     */
+    suspend fun updateAppHandleHintViewedTimestampMillis(isViewed: Boolean) {
+        dataStore.updateData { preferences ->
+            if (isViewed) {
+                preferences
+                    .toBuilder()
+                    .setAppHandleHintViewedTimestampMillis(System.currentTimeMillis())
+                    .build()
+            } else {
+                preferences.toBuilder().clearAppHandleHintViewedTimestampMillis().build()
+            }
+        }
     }
-  }
 
-  /**
-   * Updates [WindowingEducationProto.featureUsedTimestampMillis_] field in datastore with current
-   * timestamp if [isViewed] is true, if not then clears the field.
-   */
-  suspend fun updateFeatureUsedTimestampMillis(isViewed: Boolean) {
-    dataStore.updateData { preferences ->
-      if (isViewed) {
-        preferences.toBuilder().setFeatureUsedTimestampMillis(System.currentTimeMillis()).build()
-      } else {
-        preferences.toBuilder().clearFeatureUsedTimestampMillis().build()
-      }
+    /**
+     * Updates [WindowingEducationProto.appHandleHintUsedTimestampMillis_] field in datastore with
+     * current timestamp if [isViewed] is true, if not then clears the field.
+     */
+    suspend fun updateAppHandleHintUsedTimestampMillis(isViewed: Boolean) {
+        dataStore.updateData { preferences ->
+            if (isViewed) {
+                preferences
+                    .toBuilder()
+                    .setAppHandleHintUsedTimestampMillis(System.currentTimeMillis())
+                    .build()
+            } else {
+                preferences.toBuilder().clearAppHandleHintUsedTimestampMillis().build()
+            }
+        }
     }
-  }
 
-  /**
-   * Updates [AppHandleEducation.appUsageStats] and
-   * [AppHandleEducation.appUsageStatsLastUpdateTimestampMillis] fields in datastore with
-   * [appUsageStats] and [appUsageStatsLastUpdateTimestamp].
-   */
-  suspend fun updateAppUsageStats(
-      appUsageStats: Map<String, Int>,
-      appUsageStatsLastUpdateTimestamp: Duration
-  ) {
-    val currentAppHandleProto = windowingEducationProto().appHandleEducation.toBuilder()
-    currentAppHandleProto
-        .putAllAppUsageStats(appUsageStats)
-        .setAppUsageStatsLastUpdateTimestampMillis(appUsageStatsLastUpdateTimestamp.toMillis())
-    dataStore.updateData { preferences: WindowingEducationProto ->
-      preferences.toBuilder().setAppHandleEducation(currentAppHandleProto).build()
+    /**
+     * Updates [AppHandleEducation.appUsageStats] and
+     * [AppHandleEducation.appUsageStatsLastUpdateTimestampMillis] fields in datastore with
+     * [appUsageStats] and [appUsageStatsLastUpdateTimestamp].
+     */
+    suspend fun updateAppUsageStats(
+        appUsageStats: Map<String, Int>,
+        appUsageStatsLastUpdateTimestamp: Duration,
+    ) {
+        val currentAppHandleProto = windowingEducationProto().appHandleEducation.toBuilder()
+        currentAppHandleProto
+            .putAllAppUsageStats(appUsageStats)
+            .setAppUsageStatsLastUpdateTimestampMillis(appUsageStatsLastUpdateTimestamp.toMillis())
+        dataStore.updateData { preferences: WindowingEducationProto ->
+            preferences.toBuilder().setAppHandleEducation(currentAppHandleProto).build()
+        }
     }
-  }
 
-  companion object {
-    private const val TAG = "AppHandleEducationDatastoreRepository"
-    private const val APP_HANDLE_EDUCATION_DATASTORE_FILEPATH = "app_handle_education.pb"
+    companion object {
+        private const val TAG = "AppHandleEducationDatastoreRepository"
+        private const val APP_HANDLE_EDUCATION_DATASTORE_FILEPATH = "app_handle_education.pb"
 
-    object WindowingEducationProtoSerializer : Serializer<WindowingEducationProto> {
+        object WindowingEducationProtoSerializer : Serializer<WindowingEducationProto> {
 
-      override val defaultValue: WindowingEducationProto =
-          WindowingEducationProto.getDefaultInstance()
+            override val defaultValue: WindowingEducationProto =
+                WindowingEducationProto.getDefaultInstance()
 
-      override suspend fun readFrom(input: InputStream): WindowingEducationProto =
-          try {
-            WindowingEducationProto.parseFrom(input)
-          } catch (exception: InvalidProtocolBufferException) {
-            throw CorruptionException("Cannot read proto.", exception)
-          }
+            override suspend fun readFrom(input: InputStream): WindowingEducationProto =
+                try {
+                    WindowingEducationProto.parseFrom(input)
+                } catch (exception: InvalidProtocolBufferException) {
+                    throw CorruptionException("Cannot read proto.", exception)
+                }
 
-      override suspend fun writeTo(windowingProto: WindowingEducationProto, output: OutputStream) =
-          windowingProto.writeTo(output)
+            override suspend fun writeTo(
+                windowingProto: WindowingEducationProto,
+                output: OutputStream,
+            ) = windowingProto.writeTo(output)
+        }
     }
-  }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppToWebEducationDatastoreRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppToWebEducationDatastoreRepository.kt
index 8be6e6d..e5ad901 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppToWebEducationDatastoreRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppToWebEducationDatastoreRepository.kt
@@ -25,12 +25,12 @@
 import androidx.datastore.dataStoreFile
 import com.android.framework.protobuf.InvalidProtocolBufferException
 import com.android.internal.annotations.VisibleForTesting
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.catch
-import kotlinx.coroutines.flow.first
 import java.io.IOException
 import java.io.InputStream
 import java.io.OutputStream
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.first
 
 /** Updates data in App-to-Web's education datastore. */
 class AppToWebEducationDatastoreRepository
@@ -41,7 +41,9 @@
     ) : this(
         DataStoreFactory.create(
             serializer = WindowingEducationProtoSerializer,
-            produceFile = { context.dataStoreFile(APP_TO_WEB_EDUCATION_DATASTORE_FILEPATH) }))
+            produceFile = { context.dataStoreFile(APP_TO_WEB_EDUCATION_DATASTORE_FILEPATH) },
+        )
+    )
 
     /** Provides dataStore.data flow and handles exceptions thrown during collection */
     val dataStoreFlow: Flow<WindowingEducationProto> =
@@ -51,8 +53,10 @@
                 Slog.e(
                     TAG,
                     "Error in reading App-to-Web education related data from datastore," +
-                            "data is stored in a file named" +
-                            "$APP_TO_WEB_EDUCATION_DATASTORE_FILEPATH", exception)
+                        "data is stored in a file named" +
+                        "$APP_TO_WEB_EDUCATION_DATASTORE_FILEPATH",
+                    exception,
+                )
             } else {
                 throw exception
             }
@@ -72,26 +76,26 @@
         dataStore.updateData { preferences ->
             if (isViewed) {
                 preferences
-                    .toBuilder().setFeatureUsedTimestampMillis(System.currentTimeMillis()).build()
+                    .toBuilder()
+                    .setFeatureUsedTimestampMillis(System.currentTimeMillis())
+                    .build()
             } else {
                 preferences.toBuilder().clearFeatureUsedTimestampMillis().build()
             }
         }
     }
 
-    /**
-     * Increases [AppToWebEducation.educationShownCount] field by one.
-     */
+    /** Increases [AppToWebEducation.educationShownCount] field by one. */
     suspend fun updateEducationShownCount() {
         val currentAppHandleProto = windowingEducationProto().appToWebEducation.toBuilder()
-        currentAppHandleProto
-            .setEducationShownCount(currentAppHandleProto.getEducationShownCount() + 1)
+        currentAppHandleProto.setEducationShownCount(
+            currentAppHandleProto.getEducationShownCount() + 1
+        )
         dataStore.updateData { preferences ->
             preferences.toBuilder().setAppToWebEducation(currentAppHandleProto).build()
         }
     }
 
-
     companion object {
         private const val TAG = "AppToWebEducationDatastoreRepository"
         private const val APP_TO_WEB_EDUCATION_DATASTORE_FILEPATH = "app_to_web_education.pb"
@@ -110,7 +114,7 @@
 
             override suspend fun writeTo(
                 windowingProto: WindowingEducationProto,
-                output: OutputStream
+                output: OutputStream,
             ) = windowingProto.writeTo(output)
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/proto/windowing_education.proto b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/proto/windowing_education.proto
index 4cddd01..0c4d562 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/proto/windowing_education.proto
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/proto/windowing_education.proto
@@ -22,9 +22,19 @@
 // Desktop Windowing education data
 message WindowingEducationProto {
   // Timestamp in milliseconds of when the education was last viewed.
-  optional int64 education_viewed_timestamp_millis = 1;
+  optional int64 education_viewed_timestamp_millis = 1 [deprecated=true];
   // Timestamp in milliseconds of when the feature was last used.
-  optional int64 feature_used_timestamp_millis = 2;
+  optional int64 feature_used_timestamp_millis = 2 [deprecated=true];
+
+  // Timestamp in milliseconds of when the app handle hint was last viewed.
+  optional int64 app_handle_hint_viewed_timestamp_millis = 5;
+  // Timestamp in milliseconds of when the app handle hint was last used.
+  optional int64 app_handle_hint_used_timestamp_millis = 6;
+  // Timestamp in milliseconds of when the enter desktop mode hint was last viewed.
+  optional int64 enter_desktop_mode_hint_viewed_timestamp_millis = 7;
+  // Timestamp in milliseconds of when the exit desktop mode hint was last viewed.
+  optional int64 exit_desktop_mode_hint_viewed_timestamp_millis = 8;
+
   oneof education_data {
     // Fields specific to app handle education
     AppHandleEducation app_handle_education = 3;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepository.kt
index 9e646f4..b7de1f8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepository.kt
@@ -73,8 +73,8 @@
      * Reads and returns the [DesktopRepositoryState] proto object from the DataStore for a user. If
      * the DataStore is empty or there's an error reading, it returns the default value of Proto.
      */
-    private suspend fun getDesktopRepositoryState(
-        userId: Int = DEFAULT_USER_ID
+    suspend fun getDesktopRepositoryState(
+        userId: Int
     ): DesktopRepositoryState? =
         try {
             dataStoreFlow
@@ -85,12 +85,20 @@
             null
         }
 
+    suspend fun getUserDesktopRepositoryMap(): Map<Int, DesktopRepositoryState>? =
+        try {
+            dataStoreFlow.first().desktopRepoByUserMap
+        } catch (e: Exception) {
+            Log.e(TAG, "Unable to read from datastore", e)
+            null
+        }
+
     /**
      * Reads the [Desktop] of a desktop filtering by the [userId] and [desktopId]. Executes the
      * [callback] using the [mainCoroutineScope].
      */
     suspend fun readDesktop(
-        userId: Int = DEFAULT_USER_ID,
+        userId: Int,
         desktopId: Int = DEFAULT_DESKTOP_ID,
     ): Desktop? =
         try {
@@ -103,7 +111,7 @@
 
     /** Adds or updates a desktop stored in the datastore */
     suspend fun addOrUpdateDesktop(
-        userId: Int = DEFAULT_USER_ID,
+        userId: Int,
         desktopId: Int = 0,
         visibleTasks: ArraySet<Int> = ArraySet(),
         minimizedTasks: ArraySet<Int> = ArraySet(),
@@ -111,9 +119,9 @@
     ) {
         // TODO: b/367609270 - Improve the API to support multi-user
         try {
-            dataStore.updateData { desktopPersistentRepositories: DesktopPersistentRepositories ->
+            dataStore.updateData { persistentRepositories: DesktopPersistentRepositories ->
                 val currentRepository =
-                    desktopPersistentRepositories.getDesktopRepoByUserOrDefault(
+                    persistentRepositories.getDesktopRepoByUserOrDefault(
                         userId, DesktopRepositoryState.getDefaultInstance())
                 val desktop =
                     getDesktop(currentRepository, desktopId)
@@ -125,7 +133,7 @@
                         )
                         .updateZOrder(freeformTasksInZOrder)
 
-                desktopPersistentRepositories
+                persistentRepositories
                     .toBuilder()
                     .putDesktopRepoByUser(
                         userId,
@@ -135,7 +143,7 @@
                             .build())
                     .build()
             }
-        } catch (exception: IOException) {
+        } catch (exception: Exception) {
             Log.e(
                 TAG,
                 "Error in updating desktop mode related data, data is " +
@@ -154,7 +162,6 @@
         private const val TAG = "DesktopPersistenceRepo"
         private const val DESKTOP_REPOSITORIES_DATASTORE_FILE = "desktop_persistent_repositories.pb"
 
-        private const val DEFAULT_USER_ID = 1000
         private const val DEFAULT_DESKTOP_ID = 0
 
         object DesktopPersistentRepositoriesSerializer : Serializer<DesktopPersistentRepositories> {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializer.kt
index 771c3d1..a26ebbf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializer.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializer.kt
@@ -16,9 +16,9 @@
 
 package com.android.wm.shell.desktopmode.persistence
 
-import com.android.wm.shell.desktopmode.DesktopRepository
+import com.android.wm.shell.desktopmode.DesktopUserRepositories
 
-/** Interface for initializing the [DesktopRepository]. */
+/** Interface for initializing the [DesktopUserRepositories]. */
 fun interface DesktopRepositoryInitializer {
-    fun initialize(repository: DesktopRepository)
+    fun initialize(userRepositories: DesktopUserRepositories)
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerImpl.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerImpl.kt
index d815656..9539cbe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerImpl.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerImpl.kt
@@ -19,6 +19,7 @@
 import android.content.Context
 import android.window.DesktopModeFlags
 import com.android.wm.shell.desktopmode.DesktopRepository
+import com.android.wm.shell.desktopmode.DesktopUserRepositories
 import com.android.wm.shell.shared.annotations.ShellMainThread
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
 import kotlinx.coroutines.CoroutineScope
@@ -35,32 +36,52 @@
     private val persistentRepository: DesktopPersistentRepository,
     @ShellMainThread private val mainCoroutineScope: CoroutineScope,
 ) : DesktopRepositoryInitializer {
-    override fun initialize(repository: DesktopRepository) {
+    override fun initialize(userRepositories: DesktopUserRepositories) {
         if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) return
         //  TODO: b/365962554 - Handle the case that user moves to desktop before it's initialized
         mainCoroutineScope.launch {
-            val desktop = persistentRepository.readDesktop() ?: return@launch
-
-            val maxTasks =
-                DesktopModeStatus.getMaxTaskLimit(context).takeIf { it > 0 }
-                    ?: desktop.zOrderedTasksCount
-
-            var visibleTasksCount = 0
-            desktop.zOrderedTasksList
-                // Reverse it so we initialize the repo from bottom to top.
-                .reversed()
-                .mapNotNull { taskId -> desktop.tasksByTaskIdMap[taskId] }
-                .forEach { task ->
-                    if (task.desktopTaskState == DesktopTaskState.VISIBLE
-                        && visibleTasksCount < maxTasks
-                    ) {
-                        visibleTasksCount++
-                        repository.addTask(desktop.displayId, task.taskId, isVisible = false)
-                    } else {
-                        repository.addTask(desktop.displayId, task.taskId, isVisible = false)
-                        repository.minimizeTask(desktop.displayId, task.taskId)
+            val desktopUserPersistentRepositoryMap =
+                persistentRepository.getUserDesktopRepositoryMap() ?: return@launch
+            for (userId in desktopUserPersistentRepositoryMap.keys) {
+                val repository = userRepositories.getProfile(userId)
+                val desktopRepositoryState =
+                    persistentRepository.getDesktopRepositoryState(userId) ?: continue
+                val desktopByDesktopIdMap = desktopRepositoryState.desktopMap
+                for (desktopId in desktopByDesktopIdMap.keys) {
+                    val persistentDesktop =
+                        persistentRepository.readDesktop(userId, desktopId) ?: continue
+                    val maxTasks =
+                        DesktopModeStatus.getMaxTaskLimit(context).takeIf { it > 0 }
+                            ?: persistentDesktop.zOrderedTasksCount
+                    var visibleTasksCount = 0
+                    persistentDesktop.zOrderedTasksList
+                        // Reverse it so we initialize the repo from bottom to top.
+                        .reversed()
+                        .mapNotNull { taskId -> persistentDesktop.tasksByTaskIdMap[taskId] }
+                        .forEach { task ->
+                            if (task.desktopTaskState == DesktopTaskState.VISIBLE
+                                    && visibleTasksCount < maxTasks) {
+                                visibleTasksCount++
+                                repository.addTask(
+                                    persistentDesktop.displayId,
+                                    task.taskId,
+                                    isVisible = false
+                                )
+                            } else {
+                                repository.addTask(
+                                    persistentDesktop.displayId,
+                                    task.taskId,
+                                    isVisible = false
+                                )
+                                repository.minimizeTask(
+                                    persistentDesktop.displayId,
+                                    task.taskId
+                                )
+                            }
+                        }
                     }
                 }
         }
+
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
index cd20d97..a17d55f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -30,6 +30,7 @@
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.LaunchAdjacentController;
 import com.android.wm.shell.desktopmode.DesktopRepository;
+import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
@@ -49,7 +50,7 @@
 
     private final Context mContext;
     private final ShellTaskOrganizer mShellTaskOrganizer;
-    private final Optional<DesktopRepository> mDesktopRepository;
+    private final Optional<DesktopUserRepositories> mDesktopUserRepositories;
     private final Optional<DesktopTasksController> mDesktopTasksController;
     private final WindowDecorViewModel mWindowDecorationViewModel;
     private final LaunchAdjacentController mLaunchAdjacentController;
@@ -61,7 +62,7 @@
             Context context,
             ShellInit shellInit,
             ShellTaskOrganizer shellTaskOrganizer,
-            Optional<DesktopRepository> desktopRepository,
+            Optional<DesktopUserRepositories> desktopUserRepositories,
             Optional<DesktopTasksController> desktopTasksController,
             LaunchAdjacentController launchAdjacentController,
             WindowDecorViewModel windowDecorationViewModel,
@@ -69,7 +70,7 @@
         mContext = context;
         mShellTaskOrganizer = shellTaskOrganizer;
         mWindowDecorationViewModel = windowDecorationViewModel;
-        mDesktopRepository = desktopRepository;
+        mDesktopUserRepositories = desktopUserRepositories;
         mDesktopTasksController = desktopTasksController;
         mLaunchAdjacentController = launchAdjacentController;
         mTaskChangeListener = taskChangeListener;
@@ -99,8 +100,9 @@
 
         if (!DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue() &&
                 DesktopModeStatus.canEnterDesktopMode(mContext)) {
-            mDesktopRepository.ifPresent(repository -> {
-                repository.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible);
+            mDesktopUserRepositories.ifPresent(userRepositories -> {
+                DesktopRepository currentRepo = userRepositories.getProfile(taskInfo.userId);
+                currentRepo.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible);
             });
         }
         updateLaunchAdjacentController();
@@ -113,21 +115,22 @@
         mTasks.remove(taskInfo.taskId);
 
         if (!DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue() &&
-                DesktopModeStatus.canEnterDesktopMode(mContext)) {
-            mDesktopRepository.ifPresent(repository -> {
-                // TODO: b/370038902 - Handle Activity#finishAndRemoveTask.
-                if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue()
-                        || repository.isClosingTask(taskInfo.taskId)) {
-                    // A task that's vanishing should be removed:
-                    // - If it's closed by the X button which means it's marked as a closing task.
-                    repository.removeClosingTask(taskInfo.taskId);
-                    repository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId);
-                } else {
-                    repository.updateTask(taskInfo.displayId, taskInfo.taskId, /* isVisible= */
-                            false);
-                    repository.minimizeTask(taskInfo.displayId, taskInfo.taskId);
-                }
-            });
+                DesktopModeStatus.canEnterDesktopMode(mContext)
+                    && mDesktopUserRepositories.isPresent()) {
+            DesktopRepository repository =
+                    mDesktopUserRepositories.get().getProfile(taskInfo.userId);
+            // TODO: b/370038902 - Handle Activity#finishAndRemoveTask.
+            if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue()
+                    || repository.isClosingTask(taskInfo.taskId)) {
+                // A task that's vanishing should be removed:
+                // - If it's closed by the X button which means it's marked as a closing task.
+                repository.removeClosingTask(taskInfo.taskId);
+                repository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId);
+            } else {
+                repository.updateTask(taskInfo.displayId, taskInfo.taskId, /* isVisible= */
+                        false);
+                repository.minimizeTask(taskInfo.displayId, taskInfo.taskId);
+            }
         }
         mWindowDecorationViewModel.onTaskVanished(taskInfo);
         updateLaunchAdjacentController();
@@ -148,11 +151,11 @@
                 // does not propagate all task info changes.
                 mTaskChangeListener.ifPresent(listener ->
                         listener.onNonTransitionTaskChanging(taskInfo));
-            } else {
-                mDesktopRepository.ifPresent(repository -> {
-                    repository.updateTask(taskInfo.displayId, taskInfo.taskId,
-                            taskInfo.isVisible);
-                });
+            } else if (mDesktopUserRepositories.isPresent()) {
+                DesktopRepository currentRepo =
+                        mDesktopUserRepositories.get().getProfile(taskInfo.userId);
+                currentRepo.updateTask(taskInfo.displayId, taskInfo.taskId,
+                        taskInfo.isVisible);
             }
         }
         updateLaunchAdjacentController();
@@ -176,10 +179,11 @@
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG,
                 "Freeform Task Focus Changed: #%d focused=%b",
                 taskInfo.taskId, taskInfo.isFocused);
-        if (DesktopModeStatus.canEnterDesktopMode(mContext) && taskInfo.isFocused) {
-            mDesktopRepository.ifPresent(repository -> {
-                repository.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible);
-            });
+        if (DesktopModeStatus.canEnterDesktopMode(mContext) && taskInfo.isFocused
+                && mDesktopUserRepositories.isPresent()) {
+            DesktopRepository repository =
+                mDesktopUserRepositories.get().getProfile(taskInfo.userId);
+            repository.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible);
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
index e4f8333..4c316de 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
@@ -64,6 +64,7 @@
 import com.android.wm.shell.sysui.KeyguardChangeListener;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.transition.FocusTransitionObserver;
 import com.android.wm.shell.transition.Transitions;
 import com.android.wm.shell.transition.Transitions.TransitionFinishCallback;
 
@@ -89,6 +90,7 @@
 
     private final ArrayMap<IBinder, StartedTransition> mStartedTransitions = new ArrayMap<>();
     private final TaskStackListenerImpl mTaskStackListener;
+    private final FocusTransitionObserver mFocusTransitionObserver;
 
     /**
      * Local IRemoteTransition implementations registered by the keyguard service.
@@ -129,7 +131,8 @@
             @NonNull Transitions transitions,
             @NonNull TaskStackListenerImpl taskStackListener,
             @NonNull Handler mainHandler,
-            @NonNull ShellExecutor mainExecutor) {
+            @NonNull ShellExecutor mainExecutor,
+            @NonNull FocusTransitionObserver focusTransitionObserver) {
         mTransitions = transitions;
         mShellController = shellController;
         mDisplayController = displayController;
@@ -137,6 +140,7 @@
         mMainExecutor = mainExecutor;
         mTaskStackListener = taskStackListener;
         shellInit.addInitCallback(this::onInit, this);
+        mFocusTransitionObserver = focusTransitionObserver;
     }
 
     private void onInit() {
@@ -396,7 +400,8 @@
             final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
             if (taskInfo != null && taskInfo.taskId != INVALID_TASK_ID
                     && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
-                    && taskInfo.isFocused && change.getContainer() != null) {
+                    && mFocusTransitionObserver.hasGlobalFocus(taskInfo)
+                    && change.getContainer() != null) {
                 wct.setWindowingMode(change.getContainer(), WINDOWING_MODE_FULLSCREEN);
                 wct.setBounds(change.getContainer(), null);
                 return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index 5276d9d..55e90e7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -324,6 +324,8 @@
         private final @AnimationType int mAnimationType;
         private final Rect mDestinationBounds = new Rect();
 
+        private final Point mLeashOffset = new Point();
+
         private T mBaseValue;
         protected T mCurrentValue;
         protected T mStartValue;
@@ -338,13 +340,22 @@
         // Flag to avoid double-end
         private boolean mHasRequestedEnd;
 
-        private PipTransitionAnimator(TaskInfo taskInfo, SurfaceControl leash,
-                @AnimationType int animationType,
-                Rect destinationBounds, T baseValue, T startValue, T endValue) {
+        private PipTransitionAnimator(@NonNull TaskInfo taskInfo, @NonNull SurfaceControl leash,
+                @AnimationType int animationType, @NonNull Rect destinationBounds,
+                @NonNull T baseValue, @NonNull T startValue, @NonNull T endValue) {
+            this(taskInfo, leash, animationType, destinationBounds, new Point(), baseValue,
+                    startValue, endValue);
+        }
+
+        private PipTransitionAnimator(@NonNull TaskInfo taskInfo, @NonNull SurfaceControl leash,
+                @AnimationType int animationType, @NonNull Rect destinationBounds,
+                @NonNull Point leashOffset, @NonNull T baseValue, @NonNull T startValue,
+                @NonNull T endValue) {
             mTaskInfo = taskInfo;
             mLeash = leash;
             mAnimationType = animationType;
             mDestinationBounds.set(destinationBounds);
+            mLeashOffset.set(leashOffset);
             mBaseValue = baseValue;
             mStartValue = startValue;
             mEndValue = endValue;
@@ -496,6 +507,15 @@
             }
         }
 
+        /**
+         * Returns the offset of the {@link #mLeash}.
+         */
+        @NonNull
+        Point getLeashOffset() {
+            // Use copy to prevent the leash to be modified unexpectedly.
+            return new Point(mLeashOffset);
+        }
+
         void setCurrentValue(T value) {
             mCurrentValue = value;
         }
@@ -692,8 +712,8 @@
             final Rect zeroInsets = new Rect(0, 0, 0, 0);
 
             // construct new Rect instances in case they are recycled
-            return new PipTransitionAnimator<Rect>(taskInfo, leash, ANIM_TYPE_BOUNDS,
-                    endBounds, new Rect(baseBounds), new Rect(startBounds), new Rect(endBounds)) {
+            return new PipTransitionAnimator<Rect>(taskInfo, leash, ANIM_TYPE_BOUNDS, endBounds,
+                    leashOffset, new Rect(baseBounds), new Rect(startBounds), new Rect(endBounds)) {
                 private final RectEvaluator mRectEvaluator = new RectEvaluator(new Rect());
                 private final RectEvaluator mInsetsEvaluator = new RectEvaluator(new Rect());
 
@@ -720,6 +740,7 @@
                             // Use the bounds relative to the task leash in case the leash does not
                             // start from (0, 0).
                             final Rect relativeEndBounds = new Rect(end);
+                            final Point leashOffset = getLeashOffset();
                             relativeEndBounds.offset(-leashOffset.x, -leashOffset.y);
                             getSurfaceTransactionHelper()
                                     .crop(tx, leash, relativeEndBounds)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 30f1948..af18768 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -26,6 +26,8 @@
 
 import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP;
 import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString;
+import static com.android.wm.shell.desktopmode.DesktopModeUtils.calculateInitialBounds;
+import static com.android.wm.shell.desktopmode.DesktopTasksController.DESKTOP_MODE_INITIAL_BOUNDS_SCALE;
 import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
 import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
 import static com.android.wm.shell.pip.PipAnimationController.FRACTION_START;
@@ -92,6 +94,7 @@
 import com.android.wm.shell.common.pip.PipUiEventLogger;
 import com.android.wm.shell.common.pip.PipUtils;
 import com.android.wm.shell.desktopmode.DesktopRepository;
+import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.pip.phone.PipMotionHelper;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.shared.animation.Interpolators;
@@ -150,8 +153,9 @@
     private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
     private final Optional<SplitScreenController> mSplitScreenOptional;
     @Nullable private final PipPerfHintController mPipPerfHintController;
-    private final Optional<DesktopRepository> mDesktopRepositoryOptional;
+    private final Optional<DesktopUserRepositories> mDesktopUserRepositoriesOptional;
     private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
+    private final DisplayController mDisplayController;
     protected final ShellTaskOrganizer mTaskOrganizer;
     protected final ShellExecutor mMainExecutor;
 
@@ -395,7 +399,7 @@
             @NonNull PipParamsChangedForwarder pipParamsChangedForwarder,
             Optional<SplitScreenController> splitScreenOptional,
             Optional<PipPerfHintController> pipPerfHintControllerOptional,
-            Optional<DesktopRepository> desktopRepositoryOptional,
+            Optional<DesktopUserRepositories> desktopUserRepositoriesOptional,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
             @NonNull DisplayController displayController,
             @NonNull PipUiEventLogger pipUiEventLogger,
@@ -423,8 +427,9 @@
                 new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
         mSplitScreenOptional = splitScreenOptional;
         mPipPerfHintController = pipPerfHintControllerOptional.orElse(null);
-        mDesktopRepositoryOptional = desktopRepositoryOptional;
+        mDesktopUserRepositoriesOptional = desktopUserRepositoriesOptional;
         mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
+        mDisplayController = displayController;
         mTaskOrganizer = shellTaskOrganizer;
         mMainExecutor = mainExecutor;
 
@@ -754,19 +759,36 @@
     /** Returns the bounds to restore to when exiting PIP mode. */
     // TODO(b/377581840): Instead of manually tracking bounds, use bounds from Core.
     public Rect getExitDestinationBounds() {
-        if (isPipLaunchedInDesktopMode()) {
-            final Rect freeformBounds = mDesktopRepositoryOptional.get().removeBoundsBeforeMinimize(
+        if (isPipExitingToDesktopMode()) {
+            // If we are exiting PiP while device is in Desktop mode:
+            // 1) If PiP was entered via Desktop minimize (e.g. via minimize button), restore to the
+            //    previous freeform bounds that is saved in DesktopRepository.
+            // 2) If PiP was entered through other means (e.g. user swipe up), exit to initial
+            //    freeform bounds. Note that this case has a flicker at the moment (b/379984108).
+            Rect freeformBounds = getCurrentRepo().removeBoundsBeforeMinimize(
                     mTaskInfo.taskId);
-            return Objects.requireNonNullElseGet(freeformBounds, mPipBoundsState::getDisplayBounds);
+            return freeformBounds != null
+                    ? freeformBounds
+                    : calculateInitialBounds(
+                            mDisplayController.getDisplayLayout(mTaskInfo.displayId),
+                            mTaskInfo,
+                            DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
         }
         return mPipBoundsState.getDisplayBounds();
     }
 
-    /** Returns whether PiP was launched while in desktop mode. */
-    // TODO(377581840): Update this check to include non-minimized cases, e.g. split to PiP etc.
-    private boolean isPipLaunchedInDesktopMode() {
-        return Flags.enableDesktopWindowingPip() && mDesktopRepositoryOptional.isPresent()
-                && mDesktopRepositoryOptional.get().isMinimizedTask(mTaskInfo.taskId);
+    /** Returns whether PiP is exiting while we're in desktop mode. */
+    // TODO(b/377581840): Update this check to include non-minimized cases, e.g. split to PiP etc.
+    private boolean isPipExitingToDesktopMode() {
+        DesktopRepository currentRepo = getCurrentRepo();
+        return Flags.enableDesktopWindowingPip() && currentRepo != null
+                && (currentRepo.getVisibleTaskCount(mTaskInfo.displayId) > 0
+                    || isDisplayInFreeform());
+    }
+
+    private DesktopRepository getCurrentRepo() {
+        return mDesktopUserRepositoriesOptional.map(DesktopUserRepositories::getCurrent).orElse(
+                null);
     }
 
     private void exitLaunchIntoPipTask(WindowContainerTransaction wct) {
@@ -1827,23 +1849,28 @@
                 == SPLIT_POSITION_TOP_OR_LEFT;
     }
 
+    private boolean isDisplayInFreeform() {
+        final DisplayAreaInfo tdaInfo = mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(
+                mTaskInfo.displayId);
+        if (tdaInfo != null) {
+            return tdaInfo.configuration.windowConfiguration.getWindowingMode()
+                    == WINDOWING_MODE_FREEFORM;
+        }
+        return false;
+    }
+
     /**
      * The windowing mode to restore to when resizing out of PIP direction. Defaults to undefined
      * and can be overridden to restore to an alternate windowing mode.
      */
     public int getOutPipWindowingMode() {
-        final DisplayAreaInfo tdaInfo = mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(
-                mTaskInfo.displayId);
-
-        // If PiP was launched while in desktop mode (we should return the task to freeform
-        // windowing mode):
+        // If we are exiting PiP while the device is in Desktop mode (the task should expand to
+        // freeform windowing mode):
         // 1) If the display windowing mode is freeform, set windowing mode to undefined so it will
         //    resolve the windowing mode to the display's windowing mode.
         // 2) If the display windowing mode is not freeform, set windowing mode to freeform.
-        if (tdaInfo != null && isPipLaunchedInDesktopMode()) {
-            final int displayWindowingMode =
-                    tdaInfo.configuration.windowConfiguration.getWindowingMode();
-            if (displayWindowingMode == WINDOWING_MODE_FREEFORM) {
+        if (isPipExitingToDesktopMode()) {
+            if (isDisplayInFreeform()) {
                 return WINDOWING_MODE_UNDEFINED;
             } else {
                 return WINDOWING_MODE_FREEFORM;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index f7aed44..0042ec9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -73,6 +73,7 @@
 import com.android.wm.shell.common.pip.PipDisplayLayoutState;
 import com.android.wm.shell.common.pip.PipMenuController;
 import com.android.wm.shell.common.pip.PipUtils;
+import com.android.wm.shell.common.split.SplitScreenUtils;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.shared.TransitionUtil;
 import com.android.wm.shell.shared.pip.PipContentOverlay;
@@ -506,8 +507,8 @@
     }
 
     @Override
-    public void onFinishResize(TaskInfo taskInfo, Rect destinationBounds,
-            @PipAnimationController.TransitionDirection int direction,
+    public void onFinishResize(@NonNull TaskInfo taskInfo, @NonNull Rect destinationBounds,
+            @NonNull Point leashOffset, @PipAnimationController.TransitionDirection int direction,
             @NonNull SurfaceControl.Transaction tx) {
         final boolean enteringPip = isInPipDirection(direction);
         if (enteringPip) {
@@ -530,12 +531,16 @@
                 if (mFixedRotationState != FIXED_ROTATION_TRANSITION
                         && mFinishTransaction != null) {
                     mFinishTransaction.merge(tx);
-                    // Set window crop and position to destination bounds to avoid flickering.
+                    // Set crop and position to destination bounds to avoid flickering.
                     if (hasValidLeash) {
-                        mFinishTransaction.setWindowCrop(leash, destinationBounds.width(),
-                                destinationBounds.height());
-                        mFinishTransaction.setPosition(leash, destinationBounds.left,
-                                destinationBounds.top);
+                        final Rect relativeDestinationBounds = new Rect(destinationBounds);
+                        relativeDestinationBounds.offset(-leashOffset.x, -leashOffset.y);
+                        mFinishTransaction
+                                .setCrop(leash, relativeDestinationBounds)
+                                // Note that we should set the position to the start position of
+                                // leash then the visible region will be at the same place even if
+                                // the crop region doesn't start at (0, 0).
+                                .setPosition(leash, leashOffset.x, leashOffset.y);
                     }
                 }
             } else {
@@ -1266,7 +1271,8 @@
 
         mPipBoundsState.setBounds(destinationBounds);
         final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
-        onFinishResize(pipTaskInfo, destinationBounds, TRANSITION_DIRECTION_TO_PIP, tx);
+        onFinishResize(pipTaskInfo, destinationBounds, animator.getLeashOffset(),
+                TRANSITION_DIRECTION_TO_PIP, tx);
         sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
         if (swipePipToHomeOverlay != null) {
             mPipOrganizer.fadeOutAndRemoveOverlay(swipePipToHomeOverlay,
@@ -1346,6 +1352,13 @@
         return true;
     }
 
+    @Override
+    public boolean isPackageActiveInPip(@Nullable String packageName) {
+        final TaskInfo inPipTask = mPipOrganizer.getTaskInfo();
+        return packageName != null && inPipTask != null && mPipOrganizer.isInPip()
+                && packageName.equals(SplitScreenUtils.getPackageName(inPipTask.baseIntent));
+    }
+
     private void updatePipForUnhandledTransition(@NonNull TransitionInfo.Change pipChange,
             @NonNull SurfaceControl.Transaction startTransaction,
             @NonNull SurfaceControl.Transaction finishTransaction) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index 79a9ce5..6129651 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -31,6 +31,7 @@
 import android.app.TaskInfo;
 import android.content.ComponentName;
 import android.content.pm.ActivityInfo;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -92,7 +93,8 @@
                         mPipOrganizer.fadeOutAndRemoveOverlay(mPipOrganizer.mPipOverlay,
                                 null /* callback */, true /* withStartDelay*/);
                     }
-                    onFinishResize(taskInfo, animator.getDestinationBounds(), direction, tx);
+                    onFinishResize(taskInfo, animator.getDestinationBounds(),
+                            animator.getLeashOffset(), direction, tx);
                     sendOnPipTransitionFinished(direction);
                 }
 
@@ -112,9 +114,9 @@
      * Called when transition is about to finish. This is usually for performing tasks such as
      * applying WindowContainerTransaction to finalize the PiP bounds and send to the framework.
      */
-    public void onFinishResize(TaskInfo taskInfo, Rect destinationBounds,
-            @PipAnimationController.TransitionDirection int direction,
-            SurfaceControl.Transaction tx) {
+    public void onFinishResize(@NonNull TaskInfo taskInfo, @NonNull Rect destinationBounds,
+            @NonNull Point leashOffset, @PipAnimationController.TransitionDirection int direction,
+            @NonNull SurfaceControl.Transaction tx) {
     }
 
     /**
@@ -312,9 +314,8 @@
 
     /** Whether a particular package is same as current pip package. */
     public boolean isPackageActiveInPip(@Nullable String packageName) {
-        return packageName != null
-                && mPipBoundsState.getLastPipComponentName() != null
-                && packageName.equals(mPipBoundsState.getLastPipComponentName().getPackageName());
+        // No-op, to be handled differently in PIP1 and PIP2
+        return false;
     }
 
     /** Add PiP-related changes to `outWCT` for the given request. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
index 6d2df95..2c5d346 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
@@ -254,6 +254,7 @@
     @Override
     public void onConfigurationChanged(Configuration newConfiguration) {
         mPipDisplayLayoutState.onConfigurationChanged();
+        mPipTouchHandler.onConfigurationChanged();
     }
 
     @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
index 5438a01..4461a5c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.pip2.phone;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 
 import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
@@ -25,6 +26,7 @@
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.view.SurfaceControl;
+import android.window.DisplayAreaInfo;
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
@@ -33,13 +35,19 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.ProtoLog;
+import com.android.window.flags.Flags;
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
 import com.android.wm.shell.pip2.animation.PipAlphaAnimator;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 
+import java.util.Objects;
+import java.util.Optional;
+
 /**
  * Scheduler for Shell initiated PiP transitions and animations.
  */
@@ -50,6 +58,8 @@
     private final PipBoundsState mPipBoundsState;
     private final ShellExecutor mMainExecutor;
     private final PipTransitionState mPipTransitionState;
+    private final Optional<DesktopUserRepositories> mDesktopUserRepositoriesOptional;
+    private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
     private PipTransitionController mPipTransitionController;
     private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
             mSurfaceControlTransactionFactory;
@@ -61,11 +71,15 @@
     public PipScheduler(Context context,
             PipBoundsState pipBoundsState,
             ShellExecutor mainExecutor,
-            PipTransitionState pipTransitionState) {
+            PipTransitionState pipTransitionState,
+            Optional<DesktopUserRepositories> desktopUserRepositoriesOptional,
+            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
         mContext = context;
         mPipBoundsState = pipBoundsState;
         mMainExecutor = mainExecutor;
         mPipTransitionState = pipTransitionState;
+        mDesktopUserRepositoriesOptional = desktopUserRepositoriesOptional;
+        mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
 
         mSurfaceControlTransactionFactory =
                 new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
@@ -87,7 +101,7 @@
         wct.setBounds(pipTaskToken, null);
         // if we are hitting a multi-activity case
         // windowing mode change will reparent to original host task
-        wct.setWindowingMode(pipTaskToken, WINDOWING_MODE_UNDEFINED);
+        wct.setWindowingMode(pipTaskToken, getOutPipWindowingMode());
         return wct;
     }
 
@@ -241,6 +255,47 @@
         maybeUpdateMovementBounds();
     }
 
+    /** Returns whether the display is in freeform windowing mode. */
+    private boolean isDisplayInFreeform() {
+        final DisplayAreaInfo tdaInfo = mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(
+                Objects.requireNonNull(mPipTransitionState.getPipTaskInfo()).displayId);
+        if (tdaInfo != null) {
+            return tdaInfo.configuration.windowConfiguration.getWindowingMode()
+                    == WINDOWING_MODE_FREEFORM;
+        }
+        return false;
+    }
+
+    /** Returns whether PiP is exiting while we're in desktop mode. */
+    private boolean isPipExitingToDesktopMode() {
+        return Flags.enableDesktopWindowingPip() && mDesktopUserRepositoriesOptional.isPresent()
+                && (mDesktopUserRepositoriesOptional.get().getCurrent().getVisibleTaskCount(
+                Objects.requireNonNull(mPipTransitionState.getPipTaskInfo()).displayId) > 0
+                || isDisplayInFreeform());
+    }
+
+    /**
+     * The windowing mode to restore to when resizing out of PIP direction. Defaults to undefined
+     * and can be overridden to restore to an alternate windowing mode.
+     */
+    private int getOutPipWindowingMode() {
+        // If we are exiting PiP while the device is in Desktop mode (the task should expand to
+        // freeform windowing mode):
+        // 1) If the display windowing mode is freeform, set windowing mode to undefined so it will
+        //    resolve the windowing mode to the display's windowing mode.
+        // 2) If the display windowing mode is not freeform, set windowing mode to freeform.
+        if (isPipExitingToDesktopMode()) {
+            if (isDisplayInFreeform()) {
+                return WINDOWING_MODE_UNDEFINED;
+            } else {
+                return WINDOWING_MODE_FREEFORM;
+            }
+        }
+
+        // By default, or if the task is going to fullscreen, reset the windowing mode to undefined.
+        return WINDOWING_MODE_UNDEFINED;
+    }
+
     @VisibleForTesting
     void setSurfaceControlTransactionFactory(
             @NonNull PipSurfaceTransactionHelper.SurfaceControlTransactionFactory factory) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
index 65972fb..44cc563 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
@@ -363,12 +363,10 @@
         mMotionHelper.synchronizePinnedStackBounds();
         reloadResources();
 
-        /*
-        if (mPipTaskOrganizer.isInPip()) {
+        if (mPipTransitionState.isInPip()) {
             // Recreate the dismiss target for the new orientation.
             mPipDismissTargetHandler.createOrUpdateDismissTarget();
         }
-         */
     }
 
     void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index 2bcbe30..b171db2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -35,6 +35,7 @@
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.PictureInPictureParams;
+import android.app.TaskInfo;
 import android.content.Context;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -57,6 +58,7 @@
 import com.android.wm.shell.common.pip.PipDisplayLayoutState;
 import com.android.wm.shell.common.pip.PipMenuController;
 import com.android.wm.shell.common.pip.PipUtils;
+import com.android.wm.shell.common.split.SplitScreenUtils;
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.pip2.animation.PipAlphaAnimator;
 import com.android.wm.shell.pip2.animation.PipEnterAnimator;
@@ -74,8 +76,8 @@
     private static final String TAG = PipTransition.class.getSimpleName();
 
     // Used when for ENTERING_PIP state update.
-    private static final String PIP_TASK_TOKEN = "pip_task_token";
     private static final String PIP_TASK_LEASH = "pip_task_leash";
+    private static final String PIP_TASK_INFO = "pip_task_info";
 
     // Used for PiP CHANGING_BOUNDS state update.
     static final String PIP_START_TX = "pip_start_tx";
@@ -245,8 +247,8 @@
 
             // Update the PipTransitionState while supplying the PiP leash and token to be cached.
             Bundle extra = new Bundle();
-            extra.putParcelable(PIP_TASK_TOKEN, pipChange.getContainer());
             extra.putParcelable(PIP_TASK_LEASH, pipChange.getLeash());
+            extra.putParcelable(PIP_TASK_INFO, pipChange.getTaskInfo());
             mPipTransitionState.setState(PipTransitionState.ENTERING_PIP, extra);
 
             if (isInSwipePipToHomeTransition()) {
@@ -371,7 +373,9 @@
 
         // Update the src-rect-hint in params in place, to set up initial animator transform.
         Rect sourceRectHint = getAdjustedSourceRectHint(info, pipChange, pipActivityChange);
-        pipChange.getTaskInfo().pictureInPictureParams.getSourceRectHint().set(sourceRectHint);
+        final PictureInPictureParams params = getPipParams(pipChange);
+        params.copyOnlySet(
+                new PictureInPictureParams.Builder().setSourceRectHint(sourceRectHint).build());
 
         // Config-at-end transitions need to have their activities transformed before starting
         // the animation; this makes the buffer seem like it's been updated to final size.
@@ -416,9 +420,7 @@
         final SurfaceControl pipLeash = getLeash(pipChange);
         final Rect startBounds = pipChange.getStartAbsBounds();
         final Rect endBounds = pipChange.getEndAbsBounds();
-        final PictureInPictureParams params = pipChange.getTaskInfo().pictureInPictureParams != null
-                ? pipChange.getTaskInfo().pictureInPictureParams
-                : new PictureInPictureParams.Builder().build();
+        final PictureInPictureParams params = getPipParams(pipChange);
         final Rect adjustedSourceRectHint = getAdjustedSourceRectHint(info, pipChange,
                 pipActivityChange);
 
@@ -598,10 +600,10 @@
         PictureInPictureParams params = null;
         if (pipChange.getTaskInfo() != null) {
             // single activity
-            params = pipChange.getTaskInfo().pictureInPictureParams;
+            params = getPipParams(pipChange);
         } else if (parentBeforePip != null && parentBeforePip.getTaskInfo() != null) {
             // multi activity
-            params = parentBeforePip.getTaskInfo().pictureInPictureParams;
+            params = getPipParams(parentBeforePip);
         }
         final Rect sourceRectHint = PipBoundsAlgorithm.getValidSourceHintRect(params, endBounds,
                 startBounds);
@@ -625,6 +627,12 @@
             finishTransition();
         });
         cacheAndStartTransitionAnimator(animator);
+
+        // Save the PiP bounds in case, we re-enter the PiP with the same component.
+        float snapFraction = mPipBoundsAlgorithm.getSnapFraction(
+                mPipBoundsState.getBounds());
+        mPipBoundsState.saveReentryState(snapFraction);
+
         return true;
     }
 
@@ -842,19 +850,25 @@
                     initActivityPos.y);
         }
     }
-
-    @NonNull
-    private SurfaceControl getLeash(TransitionInfo.Change change) {
-        SurfaceControl leash = change.getLeash();
-        Preconditions.checkNotNull(leash, "Leash is null for change=" + change);
-        return leash;
-    }
-
     void cacheAndStartTransitionAnimator(@NonNull ValueAnimator animator) {
         mTransitionAnimator = animator;
         mTransitionAnimator.start();
     }
 
+    @NonNull
+    private static PictureInPictureParams getPipParams(@NonNull TransitionInfo.Change pipChange) {
+        return pipChange.getTaskInfo().pictureInPictureParams != null
+                ? pipChange.getTaskInfo().pictureInPictureParams
+                : new PictureInPictureParams.Builder().build();
+    }
+
+    @NonNull
+    private static SurfaceControl getLeash(TransitionInfo.Change change) {
+        SurfaceControl leash = change.getLeash();
+        Preconditions.checkNotNull(leash, "Leash is null for change=" + change);
+        return leash;
+    }
+
     //
     // Miscellaneous callbacks and listeners
     //
@@ -893,10 +907,10 @@
                 Preconditions.checkState(extra != null,
                         "No extra bundle for " + mPipTransitionState);
 
-                mPipTransitionState.setPipTaskToken(extra.getParcelable(
-                        PIP_TASK_TOKEN, WindowContainerToken.class));
                 mPipTransitionState.setPinnedTaskLeash(extra.getParcelable(
                         PIP_TASK_LEASH, SurfaceControl.class));
+                mPipTransitionState.setPipTaskInfo(extra.getParcelable(
+                        PIP_TASK_INFO, TaskInfo.class));
                 boolean hasValidTokenAndLeash = mPipTransitionState.getPipTaskToken() != null
                         && mPipTransitionState.getPinnedTaskLeash() != null;
 
@@ -904,9 +918,16 @@
                         "Unexpected bundle for " + mPipTransitionState);
                 break;
             case PipTransitionState.EXITED_PIP:
-                mPipTransitionState.setPipTaskToken(null);
                 mPipTransitionState.setPinnedTaskLeash(null);
+                mPipTransitionState.setPipTaskInfo(null);
                 break;
         }
     }
+
+    @Override
+    public boolean isPackageActiveInPip(@Nullable String packageName) {
+        final TaskInfo inPipTask = mPipTransitionState.getPipTaskInfo();
+        return packageName != null && inPipTask != null && mPipTransitionState.isInPip()
+                && packageName.equals(SplitScreenUtils.getPackageName(inPipTask.baseIntent));
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
index 8e90bfe..6f9f40a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
@@ -17,6 +17,7 @@
 package com.android.wm.shell.pip2.phone;
 
 import android.annotation.IntDef;
+import android.app.TaskInfo;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Handler;
@@ -133,17 +134,17 @@
     private final Rect mSwipePipToHomeAppBounds = new Rect();
 
     //
-    // Tokens and leashes
+    // Task related caches
     //
 
-    // pinned PiP task's WC token
-    @Nullable
-    private WindowContainerToken mPipTaskToken;
-
     // pinned PiP task's leash
     @Nullable
     private SurfaceControl mPinnedTaskLeash;
 
+    // pinned PiP task info
+    @Nullable
+    private TaskInfo mPipTaskInfo;
+
     // Overlay leash potentially used during swipe PiP to home transition;
     // if null while mInSwipePipToHomeTransition is true, then srcRectHint was invalid.
     @Nullable
@@ -305,11 +306,7 @@
     }
 
     @Nullable WindowContainerToken getPipTaskToken() {
-        return mPipTaskToken;
-    }
-
-    public void setPipTaskToken(@Nullable WindowContainerToken token) {
-        mPipTaskToken = token;
+        return mPipTaskInfo != null ? mPipTaskInfo.getToken() : null;
     }
 
     @Nullable SurfaceControl getPinnedTaskLeash() {
@@ -320,6 +317,14 @@
         mPinnedTaskLeash = leash;
     }
 
+    @Nullable TaskInfo getPipTaskInfo() {
+        return mPipTaskInfo;
+    }
+
+    void setPipTaskInfo(@Nullable TaskInfo pipTaskInfo) {
+        mPipTaskInfo = pipTaskInfo;
+    }
+
     /**
      * @return true if either in swipe or button-nav fixed rotation.
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index d917f93..441f967 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -19,8 +19,10 @@
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.content.pm.PackageManager.FEATURE_PC;
+import static android.view.Display.INVALID_DISPLAY;
 
 import static com.android.wm.shell.Flags.enableShellTopTaskTracking;
+import static com.android.wm.shell.desktopmode.DesktopWallpaperActivity.isWallpaperTask;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_OBSERVER;
 import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS;
 
@@ -53,6 +55,7 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.protolog.ProtoLog;
+import com.android.launcher3.Flags;
 import com.android.wm.shell.common.ExternalInterfaceBinder;
 import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
@@ -60,6 +63,7 @@
 import com.android.wm.shell.common.TaskStackListenerCallback;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.desktopmode.DesktopRepository;
+import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.shared.GroupedTaskInfo;
 import com.android.wm.shell.shared.annotations.ExternalThread;
@@ -69,6 +73,7 @@
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.sysui.UserChangeListener;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -86,13 +91,14 @@
  */
 public class RecentTasksController implements TaskStackListenerCallback,
         RemoteCallable<RecentTasksController>, DesktopRepository.ActiveTasksListener,
-        TaskStackTransitionObserver.TaskStackTransitionObserverListener {
+        TaskStackTransitionObserver.TaskStackTransitionObserverListener, UserChangeListener {
     private static final String TAG = RecentTasksController.class.getSimpleName();
 
     private final Context mContext;
     private final ShellController mShellController;
     private final ShellCommandHandler mShellCommandHandler;
-    private final Optional<DesktopRepository> mDesktopRepository;
+    private final Optional<DesktopUserRepositories> mDesktopUserRepositories;
+
     private final ShellExecutor mMainExecutor;
     private final TaskStackListenerImpl mTaskStackListener;
     private final RecentTasksImpl mImpl = new RecentTasksImpl();
@@ -105,6 +111,8 @@
     // Mapping of split task ids, mappings are symmetrical (ie. if t1 is the taskid of a task in a
     // pair, then mSplitTasks[t1] = t2, and mSplitTasks[t2] = t1)
     private final SparseIntArray mSplitTasks = new SparseIntArray();
+
+    private int mUserId;
     /**
      * Maps taskId to {@link SplitBounds} for both taskIDs.
      * Meaning there will be two taskId integers mapping to the same object.
@@ -130,7 +138,7 @@
             ShellCommandHandler shellCommandHandler,
             TaskStackListenerImpl taskStackListener,
             ActivityTaskManager activityTaskManager,
-            Optional<DesktopRepository> desktopRepository,
+            Optional<DesktopUserRepositories> desktopUserRepositories,
             TaskStackTransitionObserver taskStackTransitionObserver,
             @ShellMainThread ShellExecutor mainExecutor
     ) {
@@ -138,7 +146,7 @@
             return null;
         }
         return new RecentTasksController(context, shellInit, shellController, shellCommandHandler,
-                taskStackListener, activityTaskManager, desktopRepository,
+                taskStackListener, activityTaskManager, desktopUserRepositories,
                 taskStackTransitionObserver, mainExecutor);
     }
 
@@ -148,7 +156,7 @@
             ShellCommandHandler shellCommandHandler,
             TaskStackListenerImpl taskStackListener,
             ActivityTaskManager activityTaskManager,
-            Optional<DesktopRepository> desktopRepository,
+            Optional<DesktopUserRepositories> desktopUserRepositories,
             TaskStackTransitionObserver taskStackTransitionObserver,
             ShellExecutor mainExecutor) {
         mContext = context;
@@ -157,7 +165,7 @@
         mActivityTaskManager = activityTaskManager;
         mPcFeatureEnabled = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
         mTaskStackListener = taskStackListener;
-        mDesktopRepository = desktopRepository;
+        mDesktopUserRepositories = desktopUserRepositories;
         mTaskStackTransitionObserver = taskStackTransitionObserver;
         mMainExecutor = mainExecutor;
         shellInit.addInitCallback(this::onInit, this);
@@ -172,12 +180,15 @@
     }
 
     @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
-    private void onInit() {
+    void onInit() {
         mShellController.addExternalInterface(KEY_EXTRA_SHELL_RECENT_TASKS,
                 this::createExternalInterface, this);
         mShellCommandHandler.addDumpCallback(this::dump, this);
+        mUserId = ActivityManager.getCurrentUser();
+        mDesktopUserRepositories.ifPresent(
+                desktopUserRepositories ->
+                        desktopUserRepositories.getCurrent().addActiveTaskListener(this));
         mTaskStackListener.addListener(this);
-        mDesktopRepository.ifPresent(it -> it.addActiveTaskListener(this));
         mTaskStackTransitionObserver.addTaskStackTransitionObserverListener(this,
                 mMainExecutor);
         mContext.getSystemService(KeyguardManager.class).addKeyguardLockedStateListener(
@@ -282,6 +293,17 @@
         notifyRecentTasksChanged();
     }
 
+    /**
+     * This method only gets notified when a task is removed from recents as a result of another
+     * task being added to recent tasks.
+     */
+    @Override
+    public void onRecentTaskRemovedForAddTask(int taskId) {
+        mDesktopUserRepositories.ifPresent(
+                desktopUserRepositories -> desktopUserRepositories.getCurrent().removeFreeformTask(
+                        INVALID_DISPLAY, taskId));
+    }
+
     public void onTaskAdded(RunningTaskInfo taskInfo) {
         notifyRunningTaskAppeared(taskInfo);
     }
@@ -498,10 +520,9 @@
                 // If it's not in the mapping, then it was already paired with another task
                 continue;
             }
-
-            if (DesktopModeStatus.canEnterDesktopMode(mContext)
-                    && mDesktopRepository.isPresent()
-                    && mDesktopRepository.get().isActiveTask(taskInfo.taskId)) {
+            if (DesktopModeStatus.canEnterDesktopMode(mContext) &&
+                mDesktopUserRepositories.isPresent()
+                    && mDesktopUserRepositories.get().getCurrent().isActiveTask(taskInfo.taskId)) {
                 // Freeform tasks will be added as a separate entry
                 if (mostRecentFreeformTaskIndex == Integer.MAX_VALUE) {
                     mostRecentFreeformTaskIndex = groupedTasks.size();
@@ -517,7 +538,7 @@
                             taskInfo.lastNonFullscreenBounds.top);
                 }
                 freeformTasks.add(taskInfo);
-                if (mDesktopRepository.get().isMinimizedTask(taskInfo.taskId)) {
+                if (mDesktopUserRepositories.get().getCurrent().isMinimizedTask(taskInfo.taskId)) {
                     minimizedFreeformTasks.add(taskInfo.taskId);
                 }
                 continue;
@@ -530,6 +551,10 @@
                 groupedTasks.add(GroupedTaskInfo.forSplitTasks(taskInfo, pairedTaskInfo,
                         mTaskSplitBoundsMap.get(pairedTaskId)));
             } else {
+                if (Flags.enableRefactorTaskThumbnail() && isWallpaperTask(taskInfo)) {
+                    // Don't add the wallpaper task as an entry in grouped tasks
+                    continue;
+                }
                 // TODO(346588978): Consolidate multiple visible fullscreen tasks into the same
                 //  grouped task
                 groupedTasks.add(GroupedTaskInfo.forFullscreenTasks(taskInfo));
@@ -685,6 +710,21 @@
         }
     }
 
+    @Override
+    public void onUserChanged(int newUserId, @NonNull Context userContext) {
+        if (mDesktopUserRepositories.isEmpty()) return;
+
+        DesktopRepository previousUserRepository =
+                mDesktopUserRepositories.get().getProfile(mUserId);
+        mUserId = newUserId;
+        DesktopRepository currentUserRepository =
+                mDesktopUserRepositories.get().getProfile(newUserId);
+
+        // No-op if both profile ids map to the same user.
+        if (previousUserRepository.getUserId() == currentUserRepository.getUserId()) return;
+        previousUserRepository.removeActiveTasksListener(this);
+        currentUserRepository.addActiveTaskListener(this);
+    }
 
     /**
      * The interface for calls from outside the host process.
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 4f0f676..6e0e696 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
@@ -582,6 +582,7 @@
             @Nullable WindowContainerToken hideTaskToken) {
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
                 "Legacy startTask does not support hide task token");
+        if (isTaskInSplitScreenForeground(taskId)) return;
         final int[] result = new int[1];
         IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
             @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 86d6898..07c157b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -501,14 +501,22 @@
     /**
      * Deactivates main stage by removing the stage from the top level split root (usually when a
      * task underneath gets removed from the stage root).
+     * This function should always be called as part of exiting split screen.
      * @param stageToTop stage which we want to put on top
      */
     private void deactivateSplit(WindowContainerTransaction wct, @StageType int stageToTop) {
         if (enableFlexibleSplit()) {
             StageTaskListener stageToDeactivate = mStageOrderOperator.getAllStages().stream()
                     .filter(stage -> stage.getId() == stageToTop)
-                    .findFirst().orElseThrow();
-            stageToDeactivate.deactivate(wct, true /*toTop*/);
+                    .findFirst().orElse(null);
+            if (stageToDeactivate != null) {
+                stageToDeactivate.deactivate(wct, true /*toTop*/);
+            } else {
+                // If no one stage is meant to go to the top, deactivate all stages to move any
+                // child tasks out from under their respective stage root tasks.
+                mStageOrderOperator.getAllStages().forEach(stage ->
+                        stage.deactivate(wct, false /*reparentTasksToTop*/));
+            }
             mStageOrderOperator.onExitingSplit();
         } else {
             mMainStage.deactivate(wct, stageToTop == STAGE_TYPE_MAIN);
@@ -826,7 +834,14 @@
 
         setSideStagePosition(splitPosition, wct);
         options1 = options1 != null ? options1 : new Bundle();
-        addActivityOptions(options1, mSideStage);
+        StageTaskListener stageForTask1;
+        if (enableFlexibleSplit()) {
+            stageForTask1 = mStageOrderOperator.getStageForLegacyPosition(splitPosition,
+                    true /*checkAllStagesIfNotActive*/);
+        } else {
+            stageForTask1 = mSideStage;
+        }
+        addActivityOptions(options1, stageForTask1);
         wct.sendPendingIntent(pendingIntent, fillInIntent, options1);
         prepareTasksForSplitScreen(new int[] {taskId}, wct);
 
@@ -871,7 +886,14 @@
 
         setSideStagePosition(splitPosition, wct);
         options1 = options1 != null ? options1 : new Bundle();
-        addActivityOptions(options1, mSideStage);
+        StageTaskListener stageForTask1;
+        if (enableFlexibleSplit()) {
+            stageForTask1 = mStageOrderOperator.getStageForLegacyPosition(splitPosition,
+                    true /*checkAllStagesIfNotActive*/);
+        } else {
+            stageForTask1 = mSideStage;
+        }
+        addActivityOptions(options1, stageForTask1);
         wct.startShortcut(mContext.getPackageName(), shortcutInfo, options1);
         prepareTasksForSplitScreen(new int[] {taskId}, wct);
 
@@ -1003,14 +1025,29 @@
         setRootForceTranslucent(false, wct);
 
         options1 = options1 != null ? options1 : new Bundle();
-        addActivityOptions(options1, mSideStage);
+        StageTaskListener stageForTask1;
+        if (enableFlexibleSplit()) {
+            stageForTask1 = mStageOrderOperator.getStageForLegacyPosition(splitPosition,
+                    true /*checkAllStagesIfNotActive*/);
+        } else {
+            stageForTask1 = mSideStage;
+        }
+        addActivityOptions(options1, stageForTask1);
         if (shortcutInfo1 != null) {
             wct.startShortcut(mContext.getPackageName(), shortcutInfo1, options1);
         } else {
             wct.sendPendingIntent(pendingIntent1, fillInIntent1, options1);
         }
+
+        StageTaskListener stageForTask2;
+        if (enableFlexibleSplit()) {
+            stageForTask2 = mStageOrderOperator.getStageForLegacyPosition(
+                    reverseSplitPosition(splitPosition), true /*checkAllStagesIfNotActive*/);
+        } else {
+            stageForTask2 = mMainStage;
+        }
         options2 = options2 != null ? options2 : new Bundle();
-        addActivityOptions(options2, mMainStage);
+        addActivityOptions(options2, stageForTask2);
         if (shortcutInfo2 != null) {
             wct.startShortcut(mContext.getPackageName(), shortcutInfo2, options2);
         } else {
@@ -1239,6 +1276,9 @@
                     // Restore focus-ability to the windows and divider
                     wct.setFocusable(mRootTaskInfo.token, true);
 
+                    if (enableFlexibleSplit()) {
+                        mStageOrderOperator.onDoubleTappedDivider();
+                    }
                     setSideStagePosition(reverseSplitPosition(mSideStagePosition), wct);
                     mSyncQueue.queue(wct);
                     mSyncQueue.runInSync(st -> {
@@ -1848,13 +1888,21 @@
         }
         if (present) {
             updateRecentTasksSplitPair();
-        } else if (mMainStage.getChildCount() == 0 && mSideStage.getChildCount() == 0) {
-            mRecentTasks.ifPresent(recentTasks -> {
-                // remove the split pair mapping from recentTasks, and disable further updates
-                // to splits in the recents until we enter split again.
-                recentTasks.removeSplitPair(taskId);
-            });
-            dismissSplitScreen(-1, EXIT_REASON_ROOT_TASK_VANISHED);
+        } else {
+            // TODO (b/349828130): Test b/333270112 for flex split (launch adjacent for flex
+            //  currently not working)
+            boolean allRootsEmpty = enableFlexibleSplit()
+                    ? runForActiveStagesAllMatch(stageTaskListener ->
+                        stageTaskListener.getChildCount() == 0)
+                    : mMainStage.getChildCount() == 0 && mSideStage.getChildCount() == 0;
+            if (allRootsEmpty) {
+                mRecentTasks.ifPresent(recentTasks -> {
+                    // remove the split pair mapping from recentTasks, and disable further updates
+                    // to splits in the recents until we enter split again.
+                    recentTasks.removeSplitPair(taskId);
+                });
+                dismissSplitScreen(INVALID_TASK_ID, EXIT_REASON_ROOT_TASK_VANISHED);
+            }
         }
 
         for (int i = mListeners.size() - 1; i >= 0; --i) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageOrderOperator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageOrderOperator.kt
index b7b3c9b..3fa8df4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageOrderOperator.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageOrderOperator.kt
@@ -38,6 +38,7 @@
 import com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_C
 import com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString
 import com.android.wm.shell.windowdecor.WindowDecorViewModel
+import java.util.Collections
 import java.util.Optional
 
 /**
@@ -148,6 +149,24 @@
     }
 
     /**
+     * This will swap the stages for the two stages on either side of the given divider.
+     * Note: This will keep [activeStages] and [allStages] in sync by swapping both of them
+     * If there are no [activeStages] then this will be a no-op.
+     *
+     * TODO(b/379984874): Take in a divider identifier to determine which array indices to swap
+     */
+    fun onDoubleTappedDivider() {
+        if (activeStages.isEmpty()) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+                "Stages not active, ignoring swap request")
+            return
+        }
+
+        Collections.swap(activeStages, 0, 1)
+        Collections.swap(allStages, 0, 1)
+    }
+
+    /**
      * Returns a legacy split position for the given stage. If no stages are active then this will
      * return [SPLIT_POSITION_UNDEFINED]
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultSurfaceAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultSurfaceAnimator.java
index 4ea4613..d8884f6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultSurfaceAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultSurfaceAnimator.java
@@ -41,9 +41,9 @@
             @NonNull Animation anim, @NonNull SurfaceControl leash,
             @NonNull Runnable finishCallback, @NonNull TransactionPool pool,
             @NonNull ShellExecutor mainExecutor, @Nullable Point position, float cornerRadius,
-            @Nullable Rect clipRect, boolean isActivity) {
+            @Nullable Rect clipRect) {
         final DefaultAnimationAdapter adapter = new DefaultAnimationAdapter(anim, leash,
-                position, clipRect, cornerRadius, isActivity);
+                position, clipRect, cornerRadius);
         buildSurfaceAnimation(animations, anim, finishCallback, pool, mainExecutor, adapter);
     }
 
@@ -138,11 +138,9 @@
         @Nullable final Rect mClipRect;
         @Nullable private final Rect mAnimClipRect;
         final float mCornerRadius;
-        final boolean mIsActivity;
 
         DefaultAnimationAdapter(@NonNull Animation anim, @NonNull SurfaceControl leash,
-                @Nullable Point position, @Nullable Rect clipRect, float cornerRadius,
-                boolean isActivity) {
+                @Nullable Point position, @Nullable Rect clipRect, float cornerRadius) {
             super(leash);
             mAnim = anim;
             mPosition = (position != null && (position.x != 0 || position.y != 0))
@@ -150,7 +148,6 @@
             mClipRect = (clipRect != null && !clipRect.isEmpty()) ? clipRect : null;
             mAnimClipRect = mClipRect != null ? new Rect() : null;
             mCornerRadius = cornerRadius;
-            mIsActivity = isActivity;
         }
 
         @Override
@@ -160,10 +157,6 @@
             final SurfaceControl leash = mLeash;
             transformation.clear();
             mAnim.getTransformation(currentPlayTime, transformation);
-            if (com.android.graphics.libgui.flags.Flags.edgeExtensionShader()
-                    && mIsActivity && mAnim.getExtensionEdges() != 0) {
-                t.setEdgeExtensionEffect(leash, mAnim.getExtensionEdges());
-            }
             if (mPosition != null) {
                 transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
             }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 9fcf98b..e80016d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -506,6 +506,8 @@
 
                 if (!isTask && a.getExtensionEdges() != 0x0) {
                     if (com.android.graphics.libgui.flags.Flags.edgeExtensionShader()) {
+                        startTransaction.setEdgeExtensionEffect(
+                                change.getLeash(), a.getExtensionEdges());
                         finishTransaction.setEdgeExtensionEffect(change.getLeash(), /* edge */ 0);
                     } else {
                         if (!TransitionUtil.isOpeningType(mode)) {
@@ -564,7 +566,7 @@
 
                 buildSurfaceAnimation(animations, a, change.getLeash(), onAnimFinish,
                         mTransactionPool, mMainExecutor, animRelOffset, cornerRadius,
-                        clipRect, change.getActivityComponent() != null);
+                        clipRect);
 
                 final TransitionInfo.AnimationOptions options;
                 if (Flags.moveAnimationOptionsToChange()) {
@@ -876,8 +878,7 @@
         a.restrictDuration(MAX_ANIMATION_DURATION);
         a.scaleCurrentDuration(mTransitionAnimationScaleSetting);
         buildSurfaceAnimation(animations, a, wt.getSurface(), finisher, mTransactionPool,
-                mMainExecutor, change.getEndRelOffset(), cornerRadius, change.getEndAbsBounds(),
-                change.getActivityComponent() != null);
+                mMainExecutor, change.getEndRelOffset(), cornerRadius, change.getEndAbsBounds());
     }
 
     private void attachThumbnailAnimation(@NonNull ArrayList<Animator> animations,
@@ -901,8 +902,7 @@
         a.restrictDuration(MAX_ANIMATION_DURATION);
         a.scaleCurrentDuration(mTransitionAnimationScaleSetting);
         buildSurfaceAnimation(animations, a, wt.getSurface(), finisher, mTransactionPool,
-                mMainExecutor, change.getEndRelOffset(), cornerRadius, change.getEndAbsBounds(),
-                change.getActivityComponent() != null);
+                mMainExecutor, change.getEndRelOffset(), cornerRadius, change.getEndAbsBounds());
     }
 
     private static int getWallpaperTransitType(TransitionInfo info) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index 6f3aa11..aa42b7f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -347,21 +347,21 @@
             @NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
         buildSurfaceAnimation(animations, mRotateEnterAnimation, getEnterSurface(), finishCallback,
                 mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
-                null /* clipRect */, false /* isActivity */);
+                null /* clipRect */);
     }
 
     private void startScreenshotRotationAnimation(@NonNull ArrayList<Animator> animations,
             @NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
         buildSurfaceAnimation(animations, mRotateExitAnimation, mAnimLeash, finishCallback,
                 mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
-                null /* clipRect */, false /* isActivity */);
+                null /* clipRect */);
     }
 
     private void buildScreenshotAlphaAnimation(@NonNull ArrayList<Animator> animations,
             @NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
         buildSurfaceAnimation(animations, mRotateAlphaAnimation, mAnimLeash, finishCallback,
                 mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
-                null /* clipRect */, false /* isActivity */);
+                null /* clipRect */);
     }
 
     private void buildLumaAnimation(@NonNull ArrayList<Animator> animations,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index c9f2d2e..885f3db 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -63,6 +63,7 @@
 import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
 import com.android.wm.shell.shared.FocusTransitionListener;
 import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
+import com.android.wm.shell.shared.annotations.ShellMainThread;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.FocusTransitionObserver;
@@ -119,8 +120,8 @@
     public CaptionWindowDecorViewModel(
             Context context,
             Handler mainHandler,
+            @ShellMainThread ShellExecutor shellExecutor,
             @ShellBackgroundThread ShellExecutor bgExecutor,
-            ShellExecutor shellExecutor,
             Choreographer mainChoreographer,
             IWindowManager windowManager,
             ShellInit shellInit,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 982fda0..aa954fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -194,6 +194,7 @@
     @VisibleForTesting
     static void updateRelayoutParams(
             RelayoutParams relayoutParams,
+            @NonNull Context context,
             ActivityManager.RunningTaskInfo taskInfo,
             boolean applyStartTransactionOnDraw,
             boolean shouldSetTaskVisibilityPositionAndCrop,
@@ -206,9 +207,11 @@
         relayoutParams.mRunningTaskInfo = taskInfo;
         relayoutParams.mLayoutResId = R.layout.caption_window_decor;
         relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode());
-        relayoutParams.mShadowRadiusId = hasGlobalFocus
-                ? R.dimen.freeform_decor_shadow_focused_thickness
-                : R.dimen.freeform_decor_shadow_unfocused_thickness;
+        relayoutParams.mShadowRadius = hasGlobalFocus
+                ? context.getResources().getDimensionPixelSize(
+                        R.dimen.freeform_decor_shadow_focused_thickness)
+                : context.getResources().getDimensionPixelSize(
+                        R.dimen.freeform_decor_shadow_unfocused_thickness);
         relayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
         relayoutParams.mSetTaskVisibilityPositionAndCrop = shouldSetTaskVisibilityPositionAndCrop;
         relayoutParams.mIsCaptionVisible = taskInfo.isFreeform()
@@ -251,7 +254,7 @@
         final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
         final WindowContainerTransaction wct = new WindowContainerTransaction();
 
-        updateRelayoutParams(mRelayoutParams, taskInfo, applyStartTransactionOnDraw,
+        updateRelayoutParams(mRelayoutParams, mContext, taskInfo, applyStartTransactionOnDraw,
                 shouldSetTaskVisibilityPositionAndCrop, mIsStatusBarVisible,
                 mIsKeyguardVisibleAndOccluded,
                 mDisplayController.getInsetsState(taskInfo.displayId), hasGlobalFocus,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt
index b8c9151..4d95cde 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt
@@ -24,7 +24,7 @@
 import android.window.TaskSnapshot
 import androidx.compose.ui.graphics.toArgb
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
-import com.android.wm.shell.shared.desktopmode.ManageWindowsViewContainer
+import com.android.wm.shell.shared.multiinstance.ManageWindowsViewContainer
 import com.android.wm.shell.shared.split.SplitScreenConstants
 import com.android.wm.shell.splitscreen.SplitScreenController
 import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenu.kt
index dd68105..ff52a45 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenu.kt
@@ -32,8 +32,8 @@
 import com.android.window.flags.Flags
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer
 import com.android.wm.shell.common.DisplayController
-import com.android.wm.shell.desktopmode.DesktopRepository
-import com.android.wm.shell.shared.desktopmode.ManageWindowsViewContainer
+import com.android.wm.shell.desktopmode.DesktopUserRepositories
+import com.android.wm.shell.shared.multiinstance.ManageWindowsViewContainer
 import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
 import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer
 import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer
@@ -51,7 +51,7 @@
     private val displayController: DisplayController,
     private val rootTdaOrganizer: RootTaskDisplayAreaOrganizer,
     context: Context,
-    private val desktopRepository: DesktopRepository,
+    private val desktopUserRepositories: DesktopUserRepositories,
     private val surfaceControlBuilderSupplier: Supplier<SurfaceControl.Builder>,
     private val surfaceControlTransactionSupplier: Supplier<SurfaceControl.Transaction>,
     snapshotList: List<Pair<Int, TaskSnapshot>>,
@@ -76,6 +76,7 @@
         val flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
                 WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH or
                 WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+        val desktopRepository = desktopUserRepositories.getProfile(callerTaskInfo.userId)
         menuViewContainer = if (Flags.enableFullyImmersiveInDesktop()
             && desktopRepository.isTaskInFullImmersiveState(callerTaskInfo.taskId)) {
             // Use system view container so that forcibly shown system bars take effect in
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 43ed23b..e8b02dc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -39,7 +39,7 @@
 import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR;
 import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
-import static com.android.wm.shell.shared.desktopmode.ManageWindowsViewContainer.MANAGE_WINDOWS_MINIMUM_INSTANCES;
+import static com.android.wm.shell.shared.multiinstance.ManageWindowsViewContainer.MANAGE_WINDOWS_MINIMUM_INSTANCES;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
@@ -107,14 +107,21 @@
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.compatui.CompatUIController;
 import com.android.wm.shell.desktopmode.DesktopActivityOrientationChangeHandler;
+import com.android.wm.shell.desktopmode.DesktopImmersiveController;
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger;
+import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger;
+import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventEnum;
+import com.android.wm.shell.desktopmode.DesktopModeUtils;
 import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator;
 import com.android.wm.shell.desktopmode.DesktopRepository;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
 import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition;
 import com.android.wm.shell.desktopmode.DesktopTasksLimiter;
+import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.desktopmode.DesktopWallpaperActivity;
 import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository;
+import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction;
+import com.android.wm.shell.desktopmode.common.ToggleTaskSizeUtilsKt;
 import com.android.wm.shell.desktopmode.education.AppHandleEducationController;
 import com.android.wm.shell.desktopmode.education.AppToWebEducationController;
 import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
@@ -163,7 +170,7 @@
     private final ActivityTaskManager mActivityTaskManager;
     private final ShellCommandHandler mShellCommandHandler;
     private final ShellTaskOrganizer mTaskOrganizer;
-    private final DesktopRepository mDesktopRepository;
+    private final DesktopUserRepositories mDesktopUserRepositories;
     private final ShellController mShellController;
     private final Context mContext;
     private final @ShellMainThread Handler mMainHandler;
@@ -172,6 +179,7 @@
     private final DisplayController mDisplayController;
     private final SyncTransactionQueue mSyncQueue;
     private final DesktopTasksController mDesktopTasksController;
+    private final DesktopImmersiveController mDesktopImmersiveController;
     private final InputManager mInputManager;
     private final InteractionJankMonitor mInteractionJankMonitor;
     private final MultiInstanceHelper mMultiInstanceHelper;
@@ -228,6 +236,7 @@
     private final TaskPositionerFactory mTaskPositionerFactory;
     private final FocusTransitionObserver mFocusTransitionObserver;
     private final DesktopModeEventLogger mDesktopModeEventLogger;
+    private final DesktopModeUiEventLogger mDesktopModeUiEventLogger;
 
     public DesktopModeWindowDecorViewModel(
             Context context,
@@ -239,13 +248,14 @@
             ShellCommandHandler shellCommandHandler,
             IWindowManager windowManager,
             ShellTaskOrganizer taskOrganizer,
-            DesktopRepository desktopRepository,
+            DesktopUserRepositories desktopUserRepositories,
             DisplayController displayController,
             ShellController shellController,
             DisplayInsetsController displayInsetsController,
             SyncTransactionQueue syncQueue,
             Transitions transitions,
             Optional<DesktopTasksController> desktopTasksController,
+            DesktopImmersiveController desktopImmersiveController,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
             InteractionJankMonitor interactionJankMonitor,
             AppToWebGenericLinksParser genericLinksParser,
@@ -257,7 +267,8 @@
             WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
             Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
             FocusTransitionObserver focusTransitionObserver,
-            DesktopModeEventLogger desktopModeEventLogger) {
+            DesktopModeEventLogger desktopModeEventLogger,
+            DesktopModeUiEventLogger desktopModeUiEventLogger) {
         this(
                 context,
                 shellExecutor,
@@ -268,13 +279,14 @@
                 shellCommandHandler,
                 windowManager,
                 taskOrganizer,
-                desktopRepository,
+                desktopUserRepositories,
                 displayController,
                 shellController,
                 displayInsetsController,
                 syncQueue,
                 transitions,
                 desktopTasksController,
+                desktopImmersiveController,
                 genericLinksParser,
                 assistContentRequester,
                 multiInstanceHelper,
@@ -292,7 +304,8 @@
                 activityOrientationChangeHandler,
                 new TaskPositionerFactory(),
                 focusTransitionObserver,
-                desktopModeEventLogger);
+                desktopModeEventLogger,
+                desktopModeUiEventLogger);
     }
 
     @VisibleForTesting
@@ -306,13 +319,14 @@
             ShellCommandHandler shellCommandHandler,
             IWindowManager windowManager,
             ShellTaskOrganizer taskOrganizer,
-            DesktopRepository desktopRepository,
+            DesktopUserRepositories desktopUserRepositories,
             DisplayController displayController,
             ShellController shellController,
             DisplayInsetsController displayInsetsController,
             SyncTransactionQueue syncQueue,
             Transitions transitions,
             Optional<DesktopTasksController> desktopTasksController,
+            DesktopImmersiveController desktopImmersiveController,
             AppToWebGenericLinksParser genericLinksParser,
             AssistContentRequester assistContentRequester,
             MultiInstanceHelper multiInstanceHelper,
@@ -330,7 +344,8 @@
             Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
             TaskPositionerFactory taskPositionerFactory,
             FocusTransitionObserver focusTransitionObserver,
-            DesktopModeEventLogger desktopModeEventLogger) {
+            DesktopModeEventLogger desktopModeEventLogger,
+            DesktopModeUiEventLogger desktopModeUiEventLogger) {
         mContext = context;
         mMainExecutor = shellExecutor;
         mMainHandler = mainHandler;
@@ -338,13 +353,14 @@
         mBgExecutor = bgExecutor;
         mActivityTaskManager = mContext.getSystemService(ActivityTaskManager.class);
         mTaskOrganizer = taskOrganizer;
-        mDesktopRepository = desktopRepository;
+        mDesktopUserRepositories = desktopUserRepositories;
         mShellController = shellController;
         mDisplayController = displayController;
         mDisplayInsetsController = displayInsetsController;
         mSyncQueue = syncQueue;
         mTransitions = transitions;
         mDesktopTasksController = desktopTasksController.get();
+        mDesktopImmersiveController = desktopImmersiveController;
         mMultiInstanceHelper = multiInstanceHelper;
         mShellCommandHandler = shellCommandHandler;
         mWindowManager = windowManager;
@@ -393,6 +409,7 @@
         mTaskPositionerFactory = taskPositionerFactory;
         mFocusTransitionObserver = focusTransitionObserver;
         mDesktopModeEventLogger = desktopModeEventLogger;
+        mDesktopModeUiEventLogger = desktopModeUiEventLogger;
 
         shellInit.addInitCallback(this::onInit, this);
     }
@@ -567,34 +584,83 @@
                 >= MANAGE_WINDOWS_MINIMUM_INSTANCES);
     }
 
-    private void onMaximizeOrRestore(int taskId, String source, ResizeTrigger resizeTrigger,
-            MotionEvent motionEvent) {
+    private void onToggleSizeInteraction(
+            int taskId, @NonNull ToggleTaskSizeInteraction.AmbiguousSource source,
+            @Nullable MotionEvent motionEvent) {
         final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId);
         if (decoration == null) {
             return;
         }
-        mInteractionJankMonitor.begin(
-                decoration.mTaskSurface, mContext, mMainHandler,
-                Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW, source);
-        mDesktopTasksController.toggleDesktopTaskSize(decoration.mTaskInfo, resizeTrigger,
-                motionEvent);
+        final ToggleTaskSizeInteraction interaction =
+                createToggleSizeInteraction(decoration, source, motionEvent);
+        if (interaction == null) {
+            return;
+        }
+        if (interaction.getCujTracing() != null) {
+            mInteractionJankMonitor.begin(
+                    decoration.mTaskSurface, mContext, mMainHandler,
+                    interaction.getCujTracing(), interaction.getJankTag());
+        }
+        mDesktopTasksController.toggleDesktopTaskSize(decoration.mTaskInfo, interaction);
         decoration.closeHandleMenu();
         decoration.closeMaximizeMenu();
     }
 
-    private void onEnterOrExitImmersive(int taskId) {
+    private ToggleTaskSizeInteraction createToggleSizeInteraction(
+            @NonNull DesktopModeWindowDecoration decoration,
+            @NonNull ToggleTaskSizeInteraction.AmbiguousSource source,
+            @Nullable MotionEvent motionEvent) {
+        final RunningTaskInfo taskInfo = decoration.mTaskInfo;
+
+        final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(taskInfo.displayId);
+        if (displayLayout == null) {
+            return null;
+        }
+        final Rect stableBounds = new Rect();
+        displayLayout.getStableBounds(stableBounds);
+        boolean isMaximized = DesktopModeUtils.isTaskMaximized(taskInfo, stableBounds);
+
+        return new ToggleTaskSizeInteraction(
+                isMaximized
+                        ? ToggleTaskSizeInteraction.Direction.RESTORE
+                        : ToggleTaskSizeInteraction.Direction.MAXIMIZE,
+                ToggleTaskSizeUtilsKt.toSource(source, isMaximized),
+                DesktopModeEventLogger.getInputMethodFromMotionEvent(motionEvent)
+        );
+    }
+
+    private void onEnterOrExitImmersive(RunningTaskInfo taskInfo) {
+        final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
+        if (decoration == null) {
+            return;
+        }
+        final DesktopRepository desktopRepository = mDesktopUserRepositories.getProfile(
+                taskInfo.userId);
+        if (desktopRepository.isTaskInFullImmersiveState(taskInfo.taskId)) {
+            mDesktopModeUiEventLogger.log(decoration.mTaskInfo,
+                    DesktopUiEventEnum.DESKTOP_WINDOW_MAXIMIZE_BUTTON_MENU_TAP_TO_RESTORE);
+            mDesktopImmersiveController.moveTaskToNonImmersive(
+                    decoration.mTaskInfo, DesktopImmersiveController.ExitReason.USER_INTERACTION);
+        } else {
+            mDesktopModeUiEventLogger.log(decoration.mTaskInfo,
+                    DesktopUiEventEnum.DESKTOP_WINDOW_MAXIMIZE_BUTTON_MENU_TAP_TO_IMMERSIVE);
+            mDesktopImmersiveController.moveTaskToImmersive(decoration.mTaskInfo);
+        }
+        decoration.closeMaximizeMenu();
+    }
+
+    /** Snap-resize a task to the left or right side of the desktop. */
+    public void onSnapResize(int taskId, boolean left, InputMethod inputMethod, boolean fromMenu) {
         final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId);
         if (decoration == null) {
             return;
         }
-        mDesktopTasksController.toggleDesktopTaskFullImmersiveState(decoration.mTaskInfo);
-        decoration.closeMaximizeMenu();
-    }
 
-    public void onSnapResize(int taskId, boolean left, InputMethod inputMethod) {
-        final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId);
-        if (decoration == null) {
-            return;
+        if (fromMenu) {
+            final DesktopModeUiEventLogger.DesktopUiEventEnum event = left
+                    ? DesktopUiEventEnum.DESKTOP_WINDOW_MAXIMIZE_BUTTON_MENU_TAP_TO_TILE_TO_LEFT
+                    : DesktopUiEventEnum.DESKTOP_WINDOW_MAXIMIZE_BUTTON_MENU_TAP_TO_TILE_TO_RIGHT;
+            mDesktopModeUiEventLogger.log(decoration.mTaskInfo, event);
         }
 
         mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext, mMainHandler,
@@ -637,6 +703,11 @@
         decoration.addCaptionInset(wct);
         mDesktopTasksController.moveTaskToDesktop(taskId, wct, source);
         decoration.closeHandleMenu();
+
+        if (source == DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON) {
+            mDesktopModeUiEventLogger.log(decoration.mTaskInfo,
+                    DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_MENU_TAP_TO_DESKTOP_MODE);
+        }
     }
 
     private void onToFullscreen(int taskId) {
@@ -652,6 +723,8 @@
             mDesktopTasksController.moveToFullscreen(taskId,
                     DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON);
         }
+        mDesktopModeUiEventLogger.log(decoration.mTaskInfo,
+                DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_MENU_TAP_TO_FULL_SCREEN);
     }
 
     private void onToSplitScreen(int taskId) {
@@ -664,6 +737,8 @@
         // we shouldn't receive input for it any longer.
         decoration.disposeStatusBarInputLayer();
         mDesktopTasksController.requestSplit(decoration.mTaskInfo, false /* leftOrTop */);
+        mDesktopModeUiEventLogger.log(decoration.mTaskInfo,
+                DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_MENU_TAP_TO_SPLIT_SCREEN);
     }
 
     private void onNewWindow(int taskId) {
@@ -756,7 +831,6 @@
         private boolean mIsResizeGesture;
         private boolean mIsDragging;
         private boolean mTouchscreenInUse;
-        private boolean mHasLongClicked;
         private int mDragPointerId = -1;
         private MotionEvent mMotionEvent;
 
@@ -803,6 +877,11 @@
             } else if (id == R.id.back_button) {
                 mTaskOperations.injectBackKey(mDisplayId);
             } else if (id == R.id.caption_handle || id == R.id.open_menu_button) {
+                if (id == R.id.caption_handle && !decoration.mTaskInfo.isFreeform()) {
+                    // Clicking the App Handle.
+                    mDesktopModeUiEventLogger.log(decoration.mTaskInfo,
+                            DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_TAP);
+                }
                 if (!decoration.isHandleMenuActive()) {
                     moveTaskToFront(decoration.mTaskInfo);
                     openHandleMenu(mTaskId);
@@ -817,12 +896,12 @@
                         && TaskInfoKt.getRequestingImmersive(decoration.mTaskInfo)) {
                     // Task is requesting immersive, so it should either enter or exit immersive,
                     // depending on immersive state.
-                    onEnterOrExitImmersive(decoration.mTaskInfo.taskId);
+                    onEnterOrExitImmersive(decoration.mTaskInfo);
                 } else {
                     // Full immersive is disabled or task doesn't request/support it, so just
                     // toggle between maximize/restore states.
-                    onMaximizeOrRestore(decoration.mTaskInfo.taskId, "caption_bar_button",
-                            ResizeTrigger.MAXIMIZE_BUTTON, mMotionEvent);
+                    onToggleSizeInteraction(decoration.mTaskInfo.taskId,
+                            ToggleTaskSizeInteraction.AmbiguousSource.HEADER_BUTTON, mMotionEvent);
                 }
             } else if (id == R.id.minimize_window) {
                 mDesktopTasksController.minimizeTask(decoration.mTaskInfo);
@@ -910,7 +989,8 @@
                 if (decoration.isMaximizeMenuActive()) {
                     decoration.closeMaximizeMenu();
                 } else {
-                    mHasLongClicked = true;
+                    mDesktopModeUiEventLogger.log(decoration.mTaskInfo,
+                            DesktopUiEventEnum.DESKTOP_WINDOW_MAXIMIZE_BUTTON_REVEAL_MENU);
                     decoration.createMaximizeMenu();
                 }
                 return true;
@@ -947,6 +1027,8 @@
 
         private void moveTaskToFront(RunningTaskInfo taskInfo) {
             if (!mFocusTransitionObserver.hasGlobalFocus(taskInfo)) {
+                mDesktopModeUiEventLogger.log(taskInfo,
+                        DesktopUiEventEnum.DESKTOP_WINDOW_HEADER_TAP_TO_REFOCUS);
                 mDesktopTasksController.moveTaskToFront(taskInfo);
             }
         }
@@ -1003,8 +1085,10 @@
             }
             final boolean touchingButton = (id == R.id.close_window || id == R.id.maximize_window
                     || id == R.id.open_menu_button || id == R.id.minimize_window);
+            final DesktopRepository desktopRepository = mDesktopUserRepositories.getProfile(
+                    taskInfo.userId);
             final boolean dragAllowed =
-                    !mDesktopRepository.isTaskInFullImmersiveState(taskInfo.taskId);
+                    !desktopRepository.isTaskInFullImmersiveState(taskInfo.taskId);
             switch (e.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN: {
                     if (dragAllowed) {
@@ -1015,7 +1099,6 @@
                         updateDragStatus(e.getActionMasked());
                         mOnDragStartInitialBounds.set(initialBounds);
                     }
-                    mHasLongClicked = false;
                     // Do not consume input event if a button is touched, otherwise it would
                     // prevent the button's ripple effect from showing.
                     return !touchingButton;
@@ -1049,6 +1132,8 @@
                     if (!wasDragging) {
                         return false;
                     }
+                    mDesktopModeUiEventLogger.log(taskInfo,
+                            DesktopUiEventEnum.DESKTOP_WINDOW_MOVE_BY_HEADER_DRAG);
                     if (e.findPointerIndex(mDragPointerId) == -1) {
                         mDragPointerId = e.getPointerId(0);
                     }
@@ -1070,7 +1155,7 @@
                             newTaskBounds, decoration.calculateValidDragArea(),
                             new Rect(mOnDragStartInitialBounds), e,
                             mWindowDecorByTaskId.get(taskInfo.taskId));
-                    if (touchingButton && !mHasLongClicked) {
+                    if (touchingButton) {
                         // We need the input event to not be consumed here to end the ripple
                         // effect on the touched button. We will reset drag state in the ensuing
                         // onClick call that results.
@@ -1112,11 +1197,13 @@
                     && action != MotionEvent.ACTION_CANCEL)) {
                 return false;
             }
-            if (mDesktopRepository.isTaskInFullImmersiveState(mTaskId)) {
+            final DesktopRepository desktopRepository = mDesktopUserRepositories.getCurrent();
+            if (desktopRepository.isTaskInFullImmersiveState(mTaskId)) {
                 // Disallow double-tap to resize when in full immersive.
                 return false;
             }
-            onMaximizeOrRestore(mTaskId, "double_tap", ResizeTrigger.DOUBLE_TAP_APP_HEADER, e);
+            onToggleSizeInteraction(mTaskId,
+                    ToggleTaskSizeInteraction.AmbiguousSource.DOUBLE_TAP, e);
             return true;
         }
     }
@@ -1524,7 +1611,7 @@
                         mContext.createContextAsUser(UserHandle.of(taskInfo.userId), 0 /* flags */),
                         mDisplayController,
                         mSplitScreenController,
-                        mDesktopRepository,
+                        mDesktopUserRepositories,
                         mTaskOrganizer,
                         taskInfo,
                         taskSurface,
@@ -1554,23 +1641,26 @@
 
         final DesktopModeTouchEventListener touchEventListener =
                 new DesktopModeTouchEventListener(taskInfo, taskPositioner);
-        InputMethod inputMethod = DesktopModeEventLogger.Companion.getInputMethodFromMotionEvent(
-                touchEventListener.mMotionEvent);
         windowDecoration.setOnMaximizeOrRestoreClickListener(() -> {
-            onMaximizeOrRestore(taskInfo.taskId, "maximize_menu", ResizeTrigger.MAXIMIZE_MENU,
+            onToggleSizeInteraction(taskInfo.taskId,
+                    ToggleTaskSizeInteraction.AmbiguousSource.MAXIMIZE_MENU,
                     touchEventListener.mMotionEvent);
             return Unit.INSTANCE;
         });
         windowDecoration.setOnImmersiveOrRestoreClickListener(() -> {
-            onEnterOrExitImmersive(taskInfo.taskId);
+            onEnterOrExitImmersive(taskInfo);
             return Unit.INSTANCE;
         });
         windowDecoration.setOnLeftSnapClickListener(() -> {
-            onSnapResize(taskInfo.taskId, /* isLeft= */ true, inputMethod);
+            onSnapResize(taskInfo.taskId, /* isLeft= */ true,
+                    DesktopModeEventLogger.getInputMethodFromMotionEvent(
+                            touchEventListener.mMotionEvent), /* fromMenu= */ true);
             return Unit.INSTANCE;
         });
         windowDecoration.setOnRightSnapClickListener(() -> {
-            onSnapResize(taskInfo.taskId, /* isLeft= */ false, inputMethod);
+            onSnapResize(taskInfo.taskId, /* isLeft= */ false,
+                    DesktopModeEventLogger.getInputMethodFromMotionEvent(
+                            touchEventListener.mMotionEvent), /* fromMenu= */ true);
             return Unit.INSTANCE;
         });
         windowDecoration.setOnToDesktopClickListener(desktopModeTransitionSource -> {
@@ -1599,6 +1689,14 @@
             CompatUIController.launchUserAspectRatioSettings(mContext, taskInfo);
             return Unit.INSTANCE;
         });
+        windowDecoration.setOnMaximizeHoverListener(() -> {
+            if (!windowDecoration.isMaximizeMenuActive()) {
+                mDesktopModeUiEventLogger.log(taskInfo,
+                        DesktopUiEventEnum.DESKTOP_WINDOW_MAXIMIZE_BUTTON_REVEAL_MENU);
+                windowDecoration.createMaximizeMenu();
+            }
+            return Unit.INSTANCE;
+        });
         windowDecoration.setCaptionListeners(
                 touchEventListener, touchEventListener, touchEventListener, touchEventListener);
         windowDecoration.setExclusionRegionListener(mExclusionRegionListener);
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 723bbd3..bd84ccc 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
@@ -30,6 +30,7 @@
 
 import static com.android.launcher3.icons.BaseIconFactory.MODE_DEFAULT;
 import static com.android.wm.shell.shared.desktopmode.DesktopModeStatus.canEnterDesktopMode;
+import static com.android.wm.shell.shared.desktopmode.DesktopModeStatus.canEnterDesktopModeOrShowAppHandle;
 import static com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.DisabledEdge;
@@ -98,12 +99,12 @@
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.desktopmode.CaptionState;
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger;
-import com.android.wm.shell.desktopmode.DesktopRepository;
+import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository;
 import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
-import com.android.wm.shell.shared.desktopmode.ManageWindowsViewContainer;
+import com.android.wm.shell.shared.multiinstance.ManageWindowsViewContainer;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
 import com.android.wm.shell.windowdecor.viewholder.AppHandleViewHolder;
@@ -154,6 +155,7 @@
     private Function0<Unit> mOnNewWindowClickListener;
     private Function0<Unit> mOnManageWindowsClickListener;
     private Function0<Unit> mOnChangeAspectRatioClickListener;
+    private Function0<Unit> mOnMaximizeHoverListener;
     private DragPositioningCallback mDragPositioningCallback;
     private DragResizeInputListener mDragResizeListener;
     private Runnable mCurrentViewHostRunnable = null;
@@ -204,14 +206,14 @@
     private final Runnable mCapturedLinkExpiredRunnable = this::onCapturedLinkExpired;
     private final MultiInstanceHelper mMultiInstanceHelper;
     private final WindowDecorCaptionHandleRepository mWindowDecorCaptionHandleRepository;
-    private final DesktopRepository mDesktopRepository;
+    private final DesktopUserRepositories mDesktopUserRepositories;
 
     public DesktopModeWindowDecoration(
             Context context,
             @NonNull Context userContext,
             DisplayController displayController,
             SplitScreenController splitScreenController,
-            DesktopRepository desktopRepository,
+            DesktopUserRepositories desktopUserRepositories,
             ShellTaskOrganizer taskOrganizer,
             ActivityManager.RunningTaskInfo taskInfo,
             SurfaceControl taskSurface,
@@ -226,10 +228,10 @@
             MultiInstanceHelper multiInstanceHelper,
             WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
             DesktopModeEventLogger desktopModeEventLogger) {
-        this (context, userContext, displayController, splitScreenController, desktopRepository,
-                taskOrganizer, taskInfo, taskSurface, handler, bgExecutor, choreographer, syncQueue,
-                appHeaderViewHolderFactory, rootTaskDisplayAreaOrganizer, genericLinksParser,
-                assistContentRequester,
+        this (context, userContext, displayController, splitScreenController,
+                desktopUserRepositories, taskOrganizer, taskInfo, taskSurface, handler,
+                bgExecutor, choreographer, syncQueue, appHeaderViewHolderFactory,
+                rootTaskDisplayAreaOrganizer, genericLinksParser, assistContentRequester,
                 SurfaceControl.Builder::new, SurfaceControl.Transaction::new,
                 WindowContainerTransaction::new, SurfaceControl::new, new WindowManagerWrapper(
                         context.getSystemService(WindowManager.class)),
@@ -244,7 +246,7 @@
             @NonNull Context userContext,
             DisplayController displayController,
             SplitScreenController splitScreenController,
-            DesktopRepository desktopRepository,
+            DesktopUserRepositories desktopUserRepositories,
             ShellTaskOrganizer taskOrganizer,
             ActivityManager.RunningTaskInfo taskInfo,
             SurfaceControl taskSurface,
@@ -285,7 +287,7 @@
         mMultiInstanceHelper = multiInstanceHelper;
         mWindowManagerWrapper = windowManagerWrapper;
         mWindowDecorCaptionHandleRepository = windowDecorCaptionHandleRepository;
-        mDesktopRepository = desktopRepository;
+        mDesktopUserRepositories = desktopUserRepositories;
     }
 
     /**
@@ -369,6 +371,11 @@
         mOnChangeAspectRatioClickListener = listener;
     }
 
+    /** Registers a listener to be called when the maximize header button is hovered. */
+    void setOnMaximizeHoverListener(Function0<Unit> listener) {
+        mOnMaximizeHoverListener = listener;
+    }
+
     void setCaptionListeners(
             View.OnClickListener onCaptionButtonClickListener,
             View.OnTouchListener onCaptionTouchListener,
@@ -430,7 +437,7 @@
     public void updateDisabledResizingEdge(
             DragResizeWindowGeometry.DisabledEdge disabledResizingEdge, boolean shouldDelayUpdate) {
         mDisabledResizingEdge = disabledResizingEdge;
-        final boolean inFullImmersive = mDesktopRepository
+        final boolean inFullImmersive = mDesktopUserRepositories.getCurrent()
                 .isTaskInFullImmersiveState(mTaskInfo.taskId);
         if (shouldDelayUpdate) {
             return;
@@ -534,7 +541,7 @@
             mOpenByDefaultDialog.relayout(taskInfo);
         }
 
-        final boolean inFullImmersive = mDesktopRepository
+        final boolean inFullImmersive = mDesktopUserRepositories.getProfile(taskInfo.userId)
                 .isTaskInFullImmersiveState(taskInfo.taskId);
         updateRelayoutParams(mRelayoutParams, mContext, taskInfo, applyStartTransactionOnDraw,
                 shouldSetTaskVisibilityPositionAndCrop, mIsStatusBarVisible,
@@ -840,12 +847,7 @@
                     mOnCaptionGenericMotionListener,
                     mAppName,
                     mAppIconBitmap,
-                    () -> {
-                        if (!isMaximizeMenuActive()) {
-                            createMaximizeMenu();
-                        }
-                        return Unit.INSTANCE;
-                    });
+                    mOnMaximizeHoverListener);
         }
         throw new IllegalArgumentException("Unexpected layout resource id");
     }
@@ -978,10 +980,15 @@
             relayoutParams.mInputFeatures
                     |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
         }
-        if (DesktopModeStatus.useWindowShadow(/* isFocusedWindow= */ hasGlobalFocus)) {
-            relayoutParams.mShadowRadiusId = hasGlobalFocus
-                    ? R.dimen.freeform_decor_shadow_focused_thickness
-                    : R.dimen.freeform_decor_shadow_unfocused_thickness;
+        if (isAppHeader
+                && DesktopModeStatus.useWindowShadow(/* isFocusedWindow= */ hasGlobalFocus)) {
+            relayoutParams.mShadowRadius = hasGlobalFocus
+                    ? context.getResources().getDimensionPixelSize(
+                            R.dimen.freeform_decor_shadow_focused_thickness)
+                    : context.getResources().getDimensionPixelSize(
+                            R.dimen.freeform_decor_shadow_unfocused_thickness);
+        } else {
+            relayoutParams.mShadowRadius = INVALID_SHADOW_RADIUS;
         }
         relayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
         relayoutParams.mSetTaskVisibilityPositionAndCrop = shouldSetTaskVisibilityPositionAndCrop;
@@ -1295,9 +1302,11 @@
         mMaximizeMenu = mMaximizeMenuFactory.create(mSyncQueue, mRootTaskDisplayAreaOrganizer,
                 mDisplayController, mTaskInfo, mContext,
                 calculateMaximizeMenuPosition(menuWidth), mSurfaceControlTransactionSupplier);
+
         mMaximizeMenu.show(
                 /* isTaskInImmersiveMode= */ Flags.enableFullyImmersiveInDesktop()
-                        && mDesktopRepository.isTaskInFullImmersiveState(mTaskInfo.taskId),
+                        && mDesktopUserRepositories.getProfile(mTaskInfo.userId)
+                            .isTaskInFullImmersiveState(mTaskInfo.taskId),
                 /* menuWidth= */ menuWidth,
                 /* showImmersiveOption= */ Flags.enableFullyImmersiveInDesktop()
                         && TaskInfoKt.getRequestingImmersive(mTaskInfo),
@@ -1387,7 +1396,7 @@
                 && mMinimumInstancesFound;
         final boolean shouldShowChangeAspectRatioButton = HandleMenu.Companion
                 .shouldShowChangeAspectRatioButton(mTaskInfo);
-        final boolean inDesktopImmersive = mDesktopRepository
+        final boolean inDesktopImmersive = mDesktopUserRepositories.getProfile(mTaskInfo.userId)
                 .isTaskInFullImmersiveState(mTaskInfo.taskId);
         final boolean isBrowserApp = isBrowserApp();
         mHandleMenu = mHandleMenuFactory.create(
@@ -1397,10 +1406,11 @@
                 mAppIconBitmap,
                 mAppName,
                 mSplitScreenController,
-                canEnterDesktopMode(mContext),
+                canEnterDesktopModeOrShowAppHandle(mContext),
                 supportsMultiInstance,
                 shouldShowManageWindowsButton,
                 shouldShowChangeAspectRatioButton,
+                canEnterDesktopMode(mContext),
                 isBrowserApp,
                 isBrowserApp ? getAppLink() : getBrowserLink(),
                 mResult.mCaptionWidth,
@@ -1415,7 +1425,6 @@
         mHandleMenu.show(
                 /* onToDesktopClickListener= */ () -> {
                     mOnToDesktopClickListener.accept(APP_HANDLE_MENU_BUTTON);
-                    mOnToDesktopClickListener.accept(APP_HANDLE_MENU_BUTTON);
                     return Unit.INSTANCE;
                 },
                 /* onToFullscreenClickListener= */ mOnToFullscreenClickListener,
@@ -1426,7 +1435,7 @@
                 /* openInBrowserClickListener= */ (intent) -> {
                     mOpenInBrowserClickListener.accept(intent);
                     onCapturedLinkExpired();
-                    if (Flags.enableDesktopWindowingAppToWebEducation()) {
+                    if (Flags.enableDesktopWindowingAppToWebEducationIntegration()) {
                         mWindowDecorCaptionHandleRepository.onAppToWebUsage();
                     }
                     return Unit.INSTANCE;
@@ -1457,14 +1466,17 @@
             @NonNull Function1<Integer, Unit> onIconClickListener
     ) {
         if (mTaskInfo.isFreeform()) {
+            // The menu uses display-wide coordinates for positioning, so make position the sum
+            // of task position and caption position.
+            final Rect taskBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
             mManageWindowsMenu = new DesktopHeaderManageWindowsMenu(
                     mTaskInfo,
-                    /* x= */ mResult.mCaptionX,
-                    /* y= */ mResult.mCaptionY + mResult.mCaptionTopPadding,
+                    /* x= */ taskBounds.left + mResult.mCaptionX,
+                    /* y= */ taskBounds.top + mResult.mCaptionY + mResult.mCaptionTopPadding,
                     mDisplayController,
                     mRootTaskDisplayAreaOrganizer,
                     mContext,
-                    mDesktopRepository,
+                    mDesktopUserRepositories,
                     mSurfaceControlBuilderSupplier,
                     mSurfaceControlTransactionSupplier,
                     snapshotList,
@@ -1676,7 +1688,7 @@
     /** Returns true if at least one education flag is enabled. */
     private boolean isEducationEnabled() {
         return Flags.enableDesktopWindowingAppHandleEducation()
-                || Flags.enableDesktopWindowingAppToWebEducation();
+                || Flags.enableDesktopWindowingAppToWebEducationIntegration();
     }
 
     @Override
@@ -1760,7 +1772,8 @@
     void setAnimatingTaskResizeOrReposition(boolean animatingTaskResizeOrReposition) {
         if (mRelayoutParams.mLayoutResId == R.layout.desktop_mode_app_handle) return;
         final boolean inFullImmersive =
-                mDesktopRepository.isTaskInFullImmersiveState(mTaskInfo.taskId);
+                mDesktopUserRepositories.getProfile(mTaskInfo.userId)
+                        .isTaskInFullImmersiveState(mTaskInfo.taskId);
         asAppHeader(mWindowDecorViewHolder).bindData(new AppHeaderViewHolder.HeaderData(
                 mTaskInfo,
                 TaskInfoKt.getRequestingImmersive(mTaskInfo),
@@ -1788,8 +1801,9 @@
             return !animatingTaskResizeOrReposition;
         }
         final boolean inImmersiveAndRequesting =
-                mDesktopRepository.isTaskInFullImmersiveState(mTaskInfo.taskId)
-                        && TaskInfoKt.getRequestingImmersive(mTaskInfo);
+                mDesktopUserRepositories.getProfile(mTaskInfo.userId)
+                        .isTaskInFullImmersiveState(mTaskInfo.taskId)
+                    && TaskInfoKt.getRequestingImmersive(mTaskInfo);
         return !animatingTaskResizeOrReposition && !inImmersiveAndRequesting;
     }
 
@@ -1810,7 +1824,7 @@
                 @NonNull Context userContext,
                 DisplayController displayController,
                 SplitScreenController splitScreenController,
-                DesktopRepository desktopRepository,
+                DesktopUserRepositories desktopUserRepositories,
                 ShellTaskOrganizer taskOrganizer,
                 ActivityManager.RunningTaskInfo taskInfo,
                 SurfaceControl taskSurface,
@@ -1830,7 +1844,7 @@
                     userContext,
                     displayController,
                     splitScreenController,
-                    desktopRepository,
+                    desktopUserRepositories,
                     taskOrganizer,
                     taskInfo,
                     taskSurface,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index b321399..a6d503d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -460,7 +460,7 @@
                                 || ctrlType == CTRL_TYPE_RIGHT || ctrlType == CTRL_TYPE_LEFT)
                                 ? ResizeTrigger.EDGE : ResizeTrigger.CORNER;
                         mDesktopModeEventLogger.logTaskResizingStarted(mResizeTrigger,
-                                DesktopModeEventLogger.Companion.getInputMethodFromMotionEvent(e),
+                                DesktopModeEventLogger.getInputMethodFromMotionEvent(e),
                                 mTaskInfo, mDragStartTaskBounds.width(),
                                 mDragStartTaskBounds.height(), /* displayController= */ null,
                                 /* displayLayoutSize= */ mDisplayLayoutSizeSupplier.get());
@@ -514,7 +514,7 @@
                         }
 
                         mDesktopModeEventLogger.logTaskResizingEnded(mResizeTrigger,
-                                DesktopModeEventLogger.Companion.getInputMethodFromMotionEvent(
+                                DesktopModeEventLogger.getInputMethodFromMotionEvent(
                                         mLastMotionEventOnDown), mTaskInfo, taskBounds.width(),
                                 taskBounds.height(),
                                 /* displayController= */ null,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
index 6f72d34..c8aff78 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
@@ -74,8 +74,7 @@
         mFineTaskCorners = new TaskCorners(mTaskSize, fineCornerSize, disabledEdge);
 
         // Save touch areas for each edge.
-        mTaskEdges = new TaskEdges(mTaskSize, mResizeHandleEdgeOutset, mResizeHandleEdgeInset,
-                mDisabledEdge);
+        mTaskEdges = new TaskEdges(mTaskSize, mResizeHandleEdgeOutset, mDisabledEdge);
     }
 
     /**
@@ -459,7 +458,7 @@
         private final @NonNull DisabledEdge mDisabledEdge;
 
         private TaskEdges(@NonNull Size taskSize, int resizeHandleThickness,
-                int resizeHandleEdgeInset, DisabledEdge disabledEdge) {
+                DisabledEdge disabledEdge) {
             // Save touch areas for each edge.
             mDisabledEdge = disabledEdge;
             // Save touch areas for each edge.
@@ -471,16 +470,16 @@
             mLeftEdgeBounds = new Rect(
                     -resizeHandleThickness,
                     0,
-                    resizeHandleEdgeInset,
+                    resizeHandleThickness,
                     taskSize.getHeight());
             mRightEdgeBounds = new Rect(
-                    taskSize.getWidth() - resizeHandleEdgeInset,
+                    taskSize.getWidth() - resizeHandleThickness,
                     0,
                     taskSize.getWidth() + resizeHandleThickness,
                     taskSize.getHeight());
             mBottomEdgeBounds = new Rect(
                     -resizeHandleThickness,
-                    taskSize.getHeight() - resizeHandleEdgeInset,
+                    taskSize.getHeight() - resizeHandleThickness,
                     taskSize.getWidth() + resizeHandleThickness,
                     taskSize.getHeight() + resizeHandleThickness);
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
index 8a2b394..049b8d6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
@@ -76,6 +76,7 @@
     private val shouldShowNewWindowButton: Boolean,
     private val shouldShowManageWindowsButton: Boolean,
     private val shouldShowChangeAspectRatioButton: Boolean,
+    private val shouldShowDesktopModeButton: Boolean,
     private val isBrowserApp: Boolean,
     private val openInAppOrBrowserIntent: Intent?,
     private val captionWidth: Int,
@@ -186,6 +187,7 @@
             shouldShowNewWindowButton = shouldShowNewWindowButton,
             shouldShowManageWindowsButton = shouldShowManageWindowsButton,
             shouldShowChangeAspectRatioButton = shouldShowChangeAspectRatioButton,
+            shouldShowDesktopModeButton = shouldShowDesktopModeButton,
             isBrowserApp = isBrowserApp
         ).apply {
             bind(taskInfo, appIconBitmap, appName, shouldShowMoreActionsPill)
@@ -464,6 +466,7 @@
         private val shouldShowNewWindowButton: Boolean,
         private val shouldShowManageWindowsButton: Boolean,
         private val shouldShowChangeAspectRatioButton: Boolean,
+        private val shouldShowDesktopModeButton: Boolean,
         private val isBrowserApp: Boolean
     ) {
         val rootView = LayoutInflater.from(context)
@@ -660,6 +663,7 @@
             floatingBtn.isSelected = taskInfo.isPinned
             floatingBtn.isEnabled = !taskInfo.isPinned
             floatingBtn.imageTintList = style.windowingButtonColor
+            desktopBtn.isGone = !shouldShowDesktopModeButton
             desktopBtn.isSelected = taskInfo.isFreeform
             desktopBtn.isEnabled = !taskInfo.isFreeform
             desktopBtn.imageTintList = style.windowingButtonColor
@@ -741,6 +745,7 @@
         shouldShowNewWindowButton: Boolean,
         shouldShowManageWindowsButton: Boolean,
         shouldShowChangeAspectRatioButton: Boolean,
+        shouldShowDesktopModeButton: Boolean,
         isBrowserApp: Boolean,
         openInAppOrBrowserIntent: Intent?,
         captionWidth: Int,
@@ -763,6 +768,7 @@
         shouldShowNewWindowButton: Boolean,
         shouldShowManageWindowsButton: Boolean,
         shouldShowChangeAspectRatioButton: Boolean,
+        shouldShowDesktopModeButton: Boolean,
         isBrowserApp: Boolean,
         openInAppOrBrowserIntent: Intent?,
         captionWidth: Int,
@@ -781,6 +787,7 @@
             shouldShowNewWindowButton,
             shouldShowManageWindowsButton,
             shouldShowChangeAspectRatioButton,
+            shouldShowDesktopModeButton,
             isBrowserApp,
             openInAppOrBrowserIntent,
             captionWidth,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 852eee5f..584ee39 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -17,7 +17,6 @@
 package com.android.wm.shell.windowdecor;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
 import static android.view.WindowInsets.Type.captionBar;
 import static android.view.WindowInsets.Type.mandatorySystemGestures;
@@ -110,6 +109,10 @@
      * Invalid corner radius that signifies that corner radius should not be set.
      */
     static final int INVALID_CORNER_RADIUS = -1;
+    /**
+     * Invalid corner radius that signifies that shadow radius should not be set.
+     */
+    static final int INVALID_SHADOW_RADIUS = -1;
 
     /**
      * System-wide context. Only used to create context with overridden configurations.
@@ -439,16 +442,10 @@
                     .setPosition(mTaskSurface, taskPosition.x, taskPosition.y);
         }
 
-        float shadowRadius;
-        if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
-            // Shadow is not needed for fullscreen tasks
-            shadowRadius = 0;
-        } else {
-            shadowRadius =
-                    loadDimension(mDecorWindowContext.getResources(), params.mShadowRadiusId);
+        if (params.mShadowRadius != INVALID_SHADOW_RADIUS) {
+            startT.setShadowRadius(mTaskSurface, params.mShadowRadius);
+            finishT.setShadowRadius(mTaskSurface, params.mShadowRadius);
         }
-        startT.setShadowRadius(mTaskSurface, shadowRadius);
-        finishT.setShadowRadius(mTaskSurface, shadowRadius);
 
         if (params.mSetTaskVisibilityPositionAndCrop) {
             startT.show(mTaskSurface);
@@ -851,8 +848,8 @@
         @InsetsSource.Flags int mInsetSourceFlags;
         final Region mDisplayExclusionRegion = Region.obtain();
 
-        int mShadowRadiusId;
-        int mCornerRadius;
+        int mShadowRadius = INVALID_SHADOW_RADIUS;
+        int mCornerRadius = INVALID_CORNER_RADIUS;
 
         int mCaptionTopPadding;
         boolean mIsCaptionVisible;
@@ -874,8 +871,8 @@
             mInsetSourceFlags = 0;
             mDisplayExclusionRegion.setEmpty();
 
-            mShadowRadiusId = Resources.ID_NULL;
-            mCornerRadius = 0;
+            mShadowRadius = INVALID_SHADOW_RADIUS;
+            mCornerRadius = INVALID_SHADOW_RADIUS;
 
             mCaptionTopPadding = 0;
             mIsCaptionVisible = false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/DefaultWindowDecorViewHost.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/DefaultWindowDecorViewHost.kt
new file mode 100644
index 0000000..c470eef
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/DefaultWindowDecorViewHost.kt
@@ -0,0 +1,147 @@
+/*
+ * 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.common.viewhost
+
+import android.content.Context
+import android.content.res.Configuration
+import android.view.Display
+import android.view.SurfaceControl
+import android.view.SurfaceControlViewHost
+import android.view.View
+import android.view.WindowManager
+import android.view.WindowlessWindowManager
+import androidx.tracing.Trace
+import com.android.internal.annotations.VisibleForTesting
+import com.android.wm.shell.shared.annotations.ShellMainThread
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+
+typealias SurfaceControlViewHostFactory =
+    (Context, Display, WindowlessWindowManager, String) -> SurfaceControlViewHost
+
+/**
+ * A default implementation of [WindowDecorViewHost] backed by a [SurfaceControlViewHost].
+ *
+ * It does not support swapping the root view added to the VRI of the [SurfaceControlViewHost], and
+ * any attempts to do will throw, which means that once a [View] is added using [updateView] or
+ * [updateViewAsync], only its properties and binding may be changed, its children views may be
+ * added, removed or changed and its [WindowManager.LayoutParams] may be changed. It also supports
+ * asynchronously updating the view hierarchy using [updateViewAsync], in which case the update work
+ * will be posted on the [ShellMainThread] with no delay.
+ */
+class DefaultWindowDecorViewHost(
+    private val context: Context,
+    @ShellMainThread private val mainScope: CoroutineScope,
+    private val display: Display,
+    private val surfaceControlViewHostFactory: SurfaceControlViewHostFactory = { c, d, wwm, s ->
+        SurfaceControlViewHost(c, d, wwm, s)
+    },
+) : WindowDecorViewHost {
+
+    private val rootSurface: SurfaceControl =
+        SurfaceControl.Builder()
+            .setName("DefaultWindowDecorViewHost surface")
+            .setContainerLayer()
+            .setCallsite("DefaultWindowDecorViewHost#init")
+            .build()
+
+    private var wwm: WindowlessWindowManager? = null
+    @VisibleForTesting var viewHost: SurfaceControlViewHost? = null
+    private var currentUpdateJob: Job? = null
+
+    override val surfaceControl: SurfaceControl
+        get() = rootSurface
+
+    override fun updateView(
+        view: View,
+        attrs: WindowManager.LayoutParams,
+        configuration: Configuration,
+        onDrawTransaction: SurfaceControl.Transaction?,
+    ) {
+        Trace.beginSection("DefaultWindowDecorViewHost#updateView")
+        clearCurrentUpdateJob()
+        updateViewHost(view, attrs, configuration, onDrawTransaction)
+        Trace.endSection()
+    }
+
+    override fun updateViewAsync(
+        view: View,
+        attrs: WindowManager.LayoutParams,
+        configuration: Configuration,
+    ) {
+        Trace.beginSection("DefaultWindowDecorViewHost#updateViewAsync")
+        clearCurrentUpdateJob()
+        currentUpdateJob =
+            mainScope.launch {
+                updateViewHost(view, attrs, configuration, onDrawTransaction = null)
+            }
+        Trace.endSection()
+    }
+
+    override fun release(t: SurfaceControl.Transaction) {
+        clearCurrentUpdateJob()
+        viewHost?.release()
+        t.remove(rootSurface)
+    }
+
+    private fun updateViewHost(
+        view: View,
+        attrs: WindowManager.LayoutParams,
+        configuration: Configuration,
+        onDrawTransaction: SurfaceControl.Transaction?,
+    ) {
+        Trace.beginSection("DefaultWindowDecorViewHost#updateViewHost")
+        if (wwm == null) {
+            wwm = WindowlessWindowManager(configuration, rootSurface, null)
+        }
+        requireWindowlessWindowManager().setConfiguration(configuration)
+        if (viewHost == null) {
+            viewHost =
+                surfaceControlViewHostFactory.invoke(
+                    context,
+                    display,
+                    requireWindowlessWindowManager(),
+                    "DefaultWindowDecorViewHost#updateViewHost",
+                )
+        }
+        onDrawTransaction?.let { requireViewHost().rootSurfaceControl.applyTransactionOnDraw(it) }
+        if (requireViewHost().view == null) {
+            Trace.beginSection("DefaultWindowDecorViewHost#updateViewHost-setView")
+            requireViewHost().setView(view, attrs)
+            Trace.endSection()
+        } else {
+            check(requireViewHost().view == view) { "Changing view is not allowed" }
+            Trace.beginSection("DefaultWindowDecorViewHost#updateViewHost-relayout")
+            requireViewHost().relayout(attrs)
+            Trace.endSection()
+        }
+        Trace.endSection()
+    }
+
+    private fun clearCurrentUpdateJob() {
+        currentUpdateJob?.cancel()
+        currentUpdateJob = null
+    }
+
+    private fun requireWindowlessWindowManager(): WindowlessWindowManager {
+        return wwm ?: error("Expected non-null windowless window manager")
+    }
+
+    private fun requireViewHost(): SurfaceControlViewHost {
+        return viewHost ?: error("Expected non-null view host")
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/DefaultWindowDecorViewHostSupplier.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/DefaultWindowDecorViewHostSupplier.kt
new file mode 100644
index 0000000..27ffd6c
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/DefaultWindowDecorViewHostSupplier.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.common.viewhost
+
+import android.content.Context
+import android.view.Display
+import android.view.SurfaceControl
+import com.android.wm.shell.shared.annotations.ShellMainThread
+import kotlinx.coroutines.CoroutineScope
+
+/**
+ * A supplier of [DefaultWindowDecorViewHost]s. It creates a new one every time one is requested.
+ */
+class DefaultWindowDecorViewHostSupplier(@ShellMainThread private val mainScope: CoroutineScope) :
+    WindowDecorViewHostSupplier<DefaultWindowDecorViewHost> {
+
+    override fun acquire(context: Context, display: Display): DefaultWindowDecorViewHost {
+        return DefaultWindowDecorViewHost(context, mainScope, display)
+    }
+
+    override fun release(viewHost: DefaultWindowDecorViewHost, t: SurfaceControl.Transaction) {
+        viewHost.release(t)
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/WindowDecorViewHost.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/WindowDecorViewHost.kt
new file mode 100644
index 0000000..7c1479e
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/WindowDecorViewHost.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.common.viewhost
+
+import android.content.res.Configuration
+import android.view.SurfaceControl
+import android.view.View
+import android.view.WindowManager
+import com.android.wm.shell.windowdecor.WindowDecoration
+
+/**
+ * An interface for a utility that hosts a [WindowDecoration]'s [View] hierarchy under a
+ * [SurfaceControl].
+ */
+interface WindowDecorViewHost {
+    /** The surface where the underlying [View] hierarchy is being rendered. */
+    val surfaceControl: SurfaceControl
+
+    /** Synchronously update the view hierarchy of this view host. */
+    fun updateView(
+        view: View,
+        attrs: WindowManager.LayoutParams,
+        configuration: Configuration,
+        onDrawTransaction: SurfaceControl.Transaction?,
+    )
+
+    /** Asynchronously update the view hierarchy of this view host. */
+    fun updateViewAsync(view: View, attrs: WindowManager.LayoutParams, configuration: Configuration)
+
+    /** Releases the underlying [View] hierarchy and removes the backing [SurfaceControl]. */
+    fun release(t: SurfaceControl.Transaction)
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/WindowDecorViewHostSupplier.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/WindowDecorViewHostSupplier.kt
new file mode 100644
index 0000000..00e29ec
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/WindowDecorViewHostSupplier.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.common.viewhost
+
+import android.content.Context
+import android.view.Display
+import android.view.SurfaceControl
+
+/** An interface for a supplier of [WindowDecorViewHost]s. */
+interface WindowDecorViewHostSupplier<T : WindowDecorViewHost> {
+    /** Acquire a [WindowDecorViewHost]. */
+    fun acquire(context: Context, display: Display): T
+
+    /**
+     * Release a [WindowDecorViewHost] when it is no longer used.
+     *
+     * @param viewHost the [WindowDecorViewHost] to release
+     * @param t a transaction that may be used to remove any underlying backing [SurfaceControl]
+     *   that are hosting this [WindowDecorViewHost]. The supplier is not expected to apply the
+     *   transaction. It should be applied by the owner of this supplier.
+     */
+    fun release(viewHost: T, t: SurfaceControl.Transaction)
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModel.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModel.kt
index 0e40a53..9db69d5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModel.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModel.kt
@@ -33,6 +33,7 @@
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger
 import com.android.wm.shell.desktopmode.DesktopRepository
 import com.android.wm.shell.desktopmode.DesktopTasksController
+import com.android.wm.shell.desktopmode.DesktopUserRepositories
 import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator
 import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler
 import com.android.wm.shell.transition.Transitions
@@ -48,7 +49,7 @@
     private val shellTaskOrganizer: ShellTaskOrganizer,
     private val toggleResizeDesktopTaskTransitionHandler: ToggleResizeDesktopTaskTransitionHandler,
     private val returnToDragStartAnimator: ReturnToDragStartAnimator,
-    private val taskRepository: DesktopRepository,
+    private val desktopUserRepositories: DesktopUserRepositories,
     private val desktopModeEventLogger: DesktopModeEventLogger,
 ) : DisplayChangeController.OnDisplayChangingListener {
     @VisibleForTesting
@@ -81,7 +82,7 @@
                             shellTaskOrganizer,
                             toggleResizeDesktopTaskTransitionHandler,
                             returnToDragStartAnimator,
-                            taskRepository,
+                            desktopUserRepositories,
                             desktopModeEventLogger,
                         )
                     tilingTransitionHandlerByDisplayId.put(displayId, newHandler)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
index 6cdc517c..5832822 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
@@ -18,10 +18,12 @@
 
 import android.content.Context
 import android.content.res.Configuration
+import android.graphics.Path
 import android.graphics.PixelFormat
 import android.graphics.Rect
 import android.graphics.Region
 import android.os.Binder
+import android.util.Size
 import android.view.LayoutInflater
 import android.view.MotionEvent
 import android.view.RoundedCorner
@@ -40,7 +42,6 @@
 import android.view.WindowlessWindowManager
 import com.android.wm.shell.R
 import com.android.wm.shell.common.SyncTransactionQueue
-import com.android.wm.shell.desktopmode.DesktopModeEventLogger
 import java.util.function.Supplier
 
 /**
@@ -48,7 +49,7 @@
  * when two tasks are tiled on left and right to resize them simultaneously.
  */
 class DesktopTilingDividerWindowManager(
-    private val config: Configuration,
+    config: Configuration,
     private val windowName: String,
     private val context: Context,
     private val leash: SurfaceControl,
@@ -61,7 +62,11 @@
     private lateinit var viewHost: SurfaceControlViewHost
     private var tilingDividerView: TilingDividerView? = null
     private var dividerShown = false
-    private var handleRegionWidth: Int = -1
+    private var handleRegionSize: Size =
+        Size(
+            context.resources.getDimensionPixelSize(R.dimen.split_divider_handle_region_width),
+            context.resources.getDimensionPixelSize(R.dimen.split_divider_handle_region_height),
+        )
     private var setTouchRegion = true
     private val maxRoundedCornerRadius = getMaxRoundedCornerRadius()
 
@@ -74,9 +79,62 @@
         rect.set(dividerBounds)
     }
 
-    /** Sets the touch region for the SurfaceControlViewHost. */
-    fun setTouchRegion(region: Rect) {
-        setTouchRegion(viewHost.windowToken.asBinder(), Region(region))
+    /**
+     * Sets the touch region for the SurfaceControlViewHost.
+     *
+     * The region includes the area around the handle (for accessibility), the divider itself and
+     * the rounded corners (to prevent click reaching windows behind).
+     */
+    fun setTouchRegion(handle: Rect, divider: Rect, cornerRadius: Float) {
+        val path = Path()
+        path.fillType = Path.FillType.WINDING
+        // The UI starts on the top-left corner, the region will be:
+        //
+        //      cornerLeft     cornerRight
+        // c1Top        +--------+
+        //              |corners |
+        // c1Bottom     +--+  +--+
+        //                 |  |
+        //       handleLeft|  |  handleRight
+        // handleTop  +----+  +----+
+        //            |  handle    |
+        // handleBot  +----+  +----+
+        //                 |  |
+        //                 |  |
+        // c2Top        +--+  +--+
+        //              |corners |
+        // c2Bottom     +--------+
+        val cornerLeft = 0f
+        val centerX = cornerRadius + divider.width() / 2f
+        val centerY = divider.height()
+        val cornerRight = divider.width() + 2 * cornerRadius
+        val handleLeft = centerX - handle.width() / 2f
+        val handleRight = handleLeft + handle.width()
+        val dividerLeft = centerY - divider.width() / 2f
+        val dividerRight = dividerLeft + divider.width()
+
+        val c1Top = 0f
+        val c1Bottom = cornerRadius
+        val handleTop = centerY - handle.height() / 2f
+        val handleBottom = handleTop + handle.height()
+        val c2Top = divider.height() - cornerRadius
+        val c2Bottom = divider.height().toFloat()
+
+        // Top corners
+        path.addRect(cornerLeft, c1Top, cornerRight, c1Bottom, Path.Direction.CCW)
+        // Bottom corners
+        path.addRect(cornerLeft, c1Top, cornerRight, c2Bottom, Path.Direction.CCW)
+        // Handle
+        path.addRect(handleLeft, handleTop, handleRight, handleBottom, Path.Direction.CCW)
+        // Divider
+        path.addRect(dividerLeft, c2Top, dividerRight, c2Bottom, Path.Direction.CCW)
+
+        val clip = Rect(handleLeft.toInt(), c1Top.toInt(), handleRight.toInt(), c2Bottom.toInt())
+
+        val region = Region()
+        region.setPath(path, Region(clip))
+
+        setTouchRegion(viewHost.windowToken.asBinder(), region)
     }
 
     /**
@@ -96,7 +154,7 @@
         surfaceControlViewHost.setView(dividerView, lp)
         val tmpDividerBounds = Rect()
         getDividerBounds(tmpDividerBounds)
-        dividerView.setup(this, tmpDividerBounds)
+        dividerView.setup(this, tmpDividerBounds, handleRegionSize)
         t.setRelativeLayer(leash, relativeLeash, 1)
             .setPosition(
                 leash,
@@ -112,7 +170,7 @@
         viewHost = surfaceControlViewHost
         dividerView.addOnLayoutChangeListener(this)
         tilingDividerView = dividerView
-        handleRegionWidth = dividerView.handleRegionWidth
+        updateTouchRegion()
     }
 
     /** Hides the divider bar. */
@@ -176,8 +234,8 @@
     private fun getWindowManagerParams(): WindowManager.LayoutParams {
         val lp =
             WindowManager.LayoutParams(
-                dividerBounds.width() + 2 * maxRoundedCornerRadius,
-                dividerBounds.height(),
+                /* w= */ dividerBounds.width() + 2 * maxRoundedCornerRadius,
+                /* h= */ dividerBounds.height(),
                 TYPE_DOCK_DIVIDER,
                 FLAG_NOT_FOCUSABLE or
                     FLAG_NOT_TOUCH_MODAL or
@@ -216,13 +274,16 @@
     ) {
         if (!setTouchRegion) return
 
-        val startX = (dividerBounds.width() - handleRegionWidth) / 2
-        val startY = 0
-        val tempRect = Rect(startX, startY, startX + handleRegionWidth, dividerBounds.height())
-        setTouchRegion(tempRect)
+        updateTouchRegion()
         setTouchRegion = false
     }
 
+    private fun updateTouchRegion() {
+        val startX = -handleRegionSize.width / 2
+        val handle = Rect(startX, 0, startX + handleRegionSize.width, dividerBounds.height())
+        setTouchRegion(handle, dividerBounds, maxRoundedCornerRadius.toFloat())
+    }
+
     private fun setSlippery(slippery: Boolean) {
         val lp = tilingDividerView?.layoutParams as WindowManager.LayoutParams
         val isSlippery = (lp.flags and FLAG_SLIPPERY) != 0
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt
index bc7576c..7ceac52 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt
@@ -49,6 +49,7 @@
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
 import com.android.wm.shell.desktopmode.DesktopRepository
 import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition
+import com.android.wm.shell.desktopmode.DesktopUserRepositories
 import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator
 import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler
 import com.android.wm.shell.transition.Transitions
@@ -72,7 +73,7 @@
     private val shellTaskOrganizer: ShellTaskOrganizer,
     private val toggleResizeDesktopTaskTransitionHandler: ToggleResizeDesktopTaskTransitionHandler,
     private val returnToDragStartAnimator: ReturnToDragStartAnimator,
-    private val taskRepository: DesktopRepository,
+    private val desktopUserRepositories: DesktopUserRepositories,
     private val desktopModeEventLogger: DesktopModeEventLogger,
     private val transactionSupplier: Supplier<Transaction> = Supplier { Transaction() },
 ) :
@@ -492,9 +493,8 @@
 
     // Only called if [taskInfo] relates to a focused task
     private fun isTilingRefocused(taskInfo: RunningTaskInfo): Boolean {
-        return !isTilingFocused &&
-            (taskInfo.taskId == leftTaskResizingHelper?.taskInfo?.taskId ||
-                taskInfo.taskId == rightTaskResizingHelper?.taskInfo?.taskId)
+        return taskInfo.taskId == leftTaskResizingHelper?.taskInfo?.taskId ||
+                taskInfo.taskId == rightTaskResizingHelper?.taskInfo?.taskId
     }
 
     private fun buildTiledTasksMoveToFront(leftOnTop: Boolean): WindowContainerTransaction {
@@ -631,6 +631,7 @@
     private fun allTiledTasksVisible(): Boolean {
         val leftTiledTask = leftTaskResizingHelper ?: return false
         val rightTiledTask = rightTaskResizingHelper ?: return false
+        val taskRepository = desktopUserRepositories.current
         return taskRepository.isVisibleTask(leftTiledTask.taskInfo.taskId) &&
             taskRepository.isVisibleTask(rightTiledTask.taskInfo.taskId)
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt
index 111e28e..b8e3b0f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt
@@ -21,8 +21,10 @@
 import android.graphics.Rect
 import android.provider.DeviceConfig
 import android.util.AttributeSet
+import android.util.Size
 import android.view.MotionEvent
 import android.view.PointerIcon
+import android.view.RoundedCorner
 import android.view.View
 import android.view.ViewConfiguration
 import android.widget.FrameLayout
@@ -42,6 +44,7 @@
     private lateinit var callback: DividerMoveCallback
     private lateinit var handle: DividerHandleView
     private lateinit var corners: DividerRoundedCorner
+    private var cornersRadius: Int = 0
     private var touchElevation = 0
 
     private var moving = false
@@ -49,8 +52,7 @@
     var handleRegionWidth: Int = 0
     private var handleRegionHeight = 0
     private var lastAcceptedPos = 0
-    @VisibleForTesting var handleStartY = 0
-    @VisibleForTesting var handleEndY = 0
+    @VisibleForTesting var handleY: IntRange = 0..0
     private var canResize = false
     private var resized = false
     /**
@@ -79,16 +81,19 @@
     ) : super(context, attrs, defStyleAttr, defStyleRes)
 
     /** Sets up essential dependencies of the divider bar. */
-    fun setup(dividerMoveCallback: DividerMoveCallback, dividerBounds: Rect) {
+    fun setup(
+        dividerMoveCallback: DividerMoveCallback,
+        dividerBounds: Rect,
+        handleRegionSize: Size,
+    ) {
         callback = dividerMoveCallback
         this.dividerBounds.set(dividerBounds)
         handle.setIsLeftRightSplit(true)
         corners.setIsLeftRightSplit(true)
-        handleRegionHeight =
-            resources.getDimensionPixelSize(R.dimen.split_divider_handle_region_width)
-
-        handleRegionWidth =
-            resources.getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
+        handleRegionHeight = handleRegionSize.height
+        handleRegionWidth = handleRegionSize.width
+        cornersRadius =
+            context.display.getRoundedCorner(RoundedCorner.POSITION_TOP_LEFT)?.radius ?: 0
         initHandleYCoordinates()
         dragDetector =
             DragDetector(
@@ -241,17 +246,17 @@
         return true
     }
 
-    private fun isWithinHandleRegion(touchYPos: Int): Boolean {
-        return touchYPos in handleStartY..handleEndY
-    }
+    private fun isWithinHandleRegion(touchYPos: Int): Boolean = touchYPos in handleY
 
     private fun initHandleYCoordinates() {
-        handleStartY = (dividerBounds.height() - handleRegionHeight) / 2
-        handleEndY = handleStartY + handleRegionHeight
+        val handleStartY = (dividerBounds.height() - handleRegionHeight) / 2
+        val handleEndY = handleStartY + handleRegionHeight
+        handleY = handleStartY..handleEndY
     }
 
     companion object {
         const val TOUCH_ANIMATION_DURATION: Long = 150
         const val TOUCH_RELEASE_ANIMATION_DURATION: Long = 200
+        private val TAG = TilingDividerView::class.java.simpleName
     }
 }
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
index 0cc8b0c..f6d2cc0 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
@@ -25,6 +25,7 @@
 import android.tools.flicker.assertors.assertions.AppLayerIsVisibleAtStart
 import android.tools.flicker.assertors.assertions.AppWindowAlignsWithOnlyOneDisplayCornerAtEnd
 import android.tools.flicker.assertors.assertions.AppWindowBecomesInvisible
+import android.tools.flicker.assertors.assertions.AppWindowBecomesPinned
 import android.tools.flicker.assertors.assertions.AppWindowBecomesTopWindow
 import android.tools.flicker.assertors.assertions.AppWindowBecomesVisible
 import android.tools.flicker.assertors.assertions.AppWindowCoversLeftHalfScreenAtEnd
@@ -61,6 +62,14 @@
 
 class DesktopModeFlickerScenarios {
     companion object {
+        // In DesktopMode, window snap can be done with just a single window. In this case, the
+        // divider tiling between left and right window won't be shown, and hence its states are not
+        // obtainable in test.
+        // As the test should just focus on ensuring window goes to one side of the screen, an
+        // acceptable approach is to ensure snapped window still fills > 95% of either side of the
+        // screen.
+        private const val SNAP_WINDOW_MAX_DIFF_THRESHOLD_RATIO = 0.05
+
         val END_DRAG_TO_DESKTOP =
             FlickerConfigEntry(
                 scenarioId = ScenarioId("END_DRAG_TO_DESKTOP"),
@@ -229,9 +238,11 @@
                         TaggedCujTransitionMatcher(associatedTransitionRequired = false)
                     )
                     .build(),
-                assertions = AssertionTemplates.DESKTOP_MODE_APP_VISIBILITY_ASSERTIONS +
-                        listOf(AppWindowCoversLeftHalfScreenAtEnd(DESKTOP_MODE_APP))
-                            .associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
+                assertions = AssertionTemplates.DESKTOP_MODE_APP_VISIBILITY_ASSERTIONS + listOf(
+                    AppWindowCoversLeftHalfScreenAtEnd(
+                        DESKTOP_MODE_APP, SNAP_WINDOW_MAX_DIFF_THRESHOLD_RATIO
+                    )
+                ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
             )
 
         val SNAP_RESIZE_RIGHT_WITH_BUTTON =
@@ -244,9 +255,11 @@
                         TaggedCujTransitionMatcher(associatedTransitionRequired = false)
                     )
                     .build(),
-                assertions = AssertionTemplates.DESKTOP_MODE_APP_VISIBILITY_ASSERTIONS +
-                        listOf(AppWindowCoversRightHalfScreenAtEnd(DESKTOP_MODE_APP))
-                            .associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
+                assertions = AssertionTemplates.DESKTOP_MODE_APP_VISIBILITY_ASSERTIONS + listOf(
+                    AppWindowCoversRightHalfScreenAtEnd(
+                        DESKTOP_MODE_APP, SNAP_WINDOW_MAX_DIFF_THRESHOLD_RATIO
+                    )
+                ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
             )
 
         val SNAP_RESIZE_LEFT_WITH_DRAG =
@@ -465,5 +478,25 @@
                             AppWindowIsVisibleAlways(SIMPLE_APP)
                         ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
             )
+
+        val MINIMIZE_AUTO_PIP_APP =
+            FlickerConfigEntry(
+                scenarioId = ScenarioId("MINIMIZE_AUTO_PIP_APP"),
+                extractor =
+                ShellTransitionScenarioExtractor(
+                    transitionMatcher =
+                    object : ITransitionMatcher {
+                        override fun findAll(
+                            transitions: Collection<Transition>
+                        ): Collection<Transition> =
+                            transitions.filter { it.type == TransitionType.PIP }
+                    }
+                ),
+                assertions =
+                AssertionTemplates.COMMON_ASSERTIONS +
+                    listOf(
+                        AppWindowBecomesPinned(DESKTOP_MODE_APP),
+                    ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING })
+            )
     }
 }
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MinimizeAutoPipAppWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MinimizeAutoPipAppWindow.kt
new file mode 100644
index 0000000..b10db68
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MinimizeAutoPipAppWindow.kt
@@ -0,0 +1,42 @@
+/*
+ * 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.flicker
+
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.MINIMIZE_AUTO_PIP_APP
+import com.android.wm.shell.scenarios.MinimizeAutoPipAppWindow
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class MinimizeAutoPipAppWindow : MinimizeAutoPipAppWindow() {
+    @ExpectedScenarios(["MINIMIZE_AUTO_PIP_APP"])
+    @Test
+    override fun minimizePipAppWindow() = super.minimizePipAppWindow()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(MINIMIZE_AUTO_PIP_APP)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/UnmaximizeAppWindowTest.kt
similarity index 61%
copy from packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
copy to libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/UnmaximizeAppWindowTest.kt
index 83551e9..7a71d4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/UnmaximizeAppWindowTest.kt
@@ -14,15 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.phone
+package com.android.wm.shell.functional
 
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.policy.BaseHeadsUpManager
-import com.android.systemui.statusbar.policy.HeadsUpManager
-import dagger.Binds
-import dagger.Module
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.UnmaximizeAppWindow
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
 
-@Module
-interface HeadsUpModule {
-    @Binds @SysUISingleton fun bindsHeadsUpManager(hum: BaseHeadsUpManager): HeadsUpManager
-}
+/* Functional test for [UnmaximizeAppWindow]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class UnmaximizeAppWindowTest : UnmaximizeAppWindow()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt
index c43a575..bb812ad 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt
@@ -45,9 +45,9 @@
     @Before
     fun setup() {
         Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+        testApp.enterDesktopMode(wmHelper, device)
         // Set string extra to ensure the app is on PiP mode at launch
         pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = mapOf("enter_pip" to "true"))
-        testApp.enterDesktopMode(wmHelper, device)
         mailApp.launchViaIntent(wmHelper)
         newTasksApp.launchViaIntent(wmHelper)
         imeApp.launchViaIntent(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt
index 0226eb3..41452c3 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt
@@ -63,9 +63,9 @@
         Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
         tapl.setEnableRotation(true)
         tapl.setExpectedRotation(rotation.value)
+        testApp.enterDesktopMode(wmHelper, device)
         // Set string extra to ensure the app is on PiP mode at launch
         pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = mapOf("enter_pip" to "true"))
-        testApp.enterDesktopMode(wmHelper, device)
         mailApp.launchViaIntent(wmHelper)
         newTasksApp.launchViaIntent(wmHelper)
         imeApp.launchViaIntent(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/UnmaximizeAppWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/UnmaximizeAppWindow.kt
new file mode 100644
index 0000000..7411250
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/UnmaximizeAppWindow.kt
@@ -0,0 +1,80 @@
+/*
+ * 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.scenarios
+
+import android.app.Instrumentation
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.window.flags.Flags
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+/**
+ * Testing "unmaximizing" a window e.g. making it get out of/exit a window that was already
+ * maximized.
+ */
+@Ignore("Test Base Class")
+abstract class UnmaximizeAppWindow
+constructor(private val rotation: Rotation = Rotation.ROTATION_0, isResizable: Boolean = true) {
+
+    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    private val tapl = LauncherInstrumentation()
+    private val wmHelper = WindowManagerStateHelper(instrumentation)
+    private val device = UiDevice.getInstance(instrumentation)
+    private val testApp = if (isResizable) {
+        DesktopModeAppHelper(SimpleAppHelper(instrumentation))
+    } else {
+        DesktopModeAppHelper(NonResizeableAppHelper(instrumentation))
+    }
+
+    @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+    @Before
+    fun setup() {
+        Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+        tapl.setEnableRotation(true)
+        tapl.setExpectedRotation(rotation.value)
+        ChangeDisplayOrientationRule.setRotation(rotation)
+        testApp.enterDesktopMode(wmHelper, device)
+        // Press the buttonn once to setup app window to be maximized already
+        testApp.maximiseDesktopApp(wmHelper, device)
+    }
+
+    @Test
+    open fun unmaximizeAppWindow() {
+        // Re-press button to exit maximized state
+        testApp.maximiseDesktopApp(wmHelper, device)
+    }
+
+    @After
+    fun teardown() {
+        testApp.exit(wmHelper)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/Android.bp b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/Android.bp
index 176020f..6d12b00 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/Android.bp
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/Android.bp
@@ -49,6 +49,7 @@
         "wm-flicker-common-assertions",
         "launcher-helper-lib",
         "launcher-aosp-tapl",
+        "com_android_wm_shell_flags_lib",
     ],
 }
 
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/AndroidTestTemplate.xml
index 706c632..1de47df 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/AndroidTestTemplate.xml
@@ -48,6 +48,8 @@
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="test-user-token" value="%TEST_USER%"/>
         <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
+        <!-- Disable AOD -->
+        <option name="run-command" value="settings put secure doze_always_on 0"/>
         <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
         <option name="run-command" value="settings put system show_touches 1"/>
         <option name="run-command" value="settings put system pointer_location 1"/>
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
index 6d396ea..9c71510 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
@@ -17,12 +17,16 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
+import android.platform.test.flag.junit.CheckFlagsRule
+import android.platform.test.flag.junit.DeviceFlagsValueProvider
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
 import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.splitscreen.benchmark.DismissSplitScreenByGoHomeBenchmark
 import com.android.wm.shell.flicker.utils.ICommonAssertions
 import com.android.wm.shell.flicker.utils.appWindowBecomesInvisible
@@ -30,6 +34,7 @@
 import com.android.wm.shell.flicker.utils.splitAppLayerBoundsBecomesInvisible
 import com.android.wm.shell.flicker.utils.splitScreenDividerBecomesInvisible
 import org.junit.FixMethodOrder
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -44,8 +49,13 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class DismissSplitScreenByGoHome(override val flicker: LegacyFlickerTest) :
     DismissSplitScreenByGoHomeBenchmark(flicker), ICommonAssertions {
+    @JvmField
+    @Rule
+    val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             defaultSetup(this)
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-service/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-service/AndroidTestTemplate.xml
index 7df1675..34d001c 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-service/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-service/AndroidTestTemplate.xml
@@ -48,6 +48,8 @@
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="test-user-token" value="%TEST_USER%"/>
         <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
+        <!-- Disable AOD -->
+        <option name="run-command" value="settings put secure doze_always_on 0"/>
         <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
         <option name="run-command" value="settings put system show_touches 1"/>
         <option name="run-command" value="settings put system pointer_location 1"/>
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/platinum/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/e2e/splitscreen/platinum/AndroidTestTemplate.xml
index 7df1675..34d001c 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/platinum/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/platinum/AndroidTestTemplate.xml
@@ -48,6 +48,8 @@
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="test-user-token" value="%TEST_USER%"/>
         <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
+        <!-- Disable AOD -->
+        <option name="run-command" value="settings put secure doze_always_on 0"/>
         <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
         <option name="run-command" value="settings put system show_touches 1"/>
         <option name="run-command" value="settings put system pointer_location 1"/>
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/appcompat/AndroidTestTemplate.xml
index d87c179..9c1a8f1 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/AndroidTestTemplate.xml
@@ -48,6 +48,8 @@
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="test-user-token" value="%TEST_USER%"/>
         <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
+        <!-- Disable AOD -->
+        <option name="run-command" value="settings put secure doze_always_on 0"/>
         <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
         <option name="run-command" value="settings put system show_touches 1"/>
         <option name="run-command" value="settings put system pointer_location 1"/>
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml
index 99969e7..02b2cec 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml
@@ -48,6 +48,8 @@
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="test-user-token" value="%TEST_USER%"/>
         <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
+        <!-- Disable AOD -->
+        <option name="run-command" value="settings put secure doze_always_on 0"/>
         <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
         <option name="run-command" value="settings put system show_touches 1"/>
         <option name="run-command" value="settings put system pointer_location 1"/>
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml
index 19c3e40..a136936 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml
@@ -25,7 +25,7 @@
         <!-- keeps the screen on during tests -->
         <option name="screen-always-on" value="on"/>
         <!-- Turns off Wi-fi -->
-        <option name="wifi" value="off"/>
+        <option name="wifi" value="on"/>
         <!-- Turns off Bluetooth -->
         <option name="bluetooth" value="off"/>
         <!-- prevents the phone from restarting -->
@@ -48,6 +48,8 @@
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="test-user-token" value="%TEST_USER%"/>
         <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
+        <!-- Disable AOD -->
+        <option name="run-command" value="settings put secure doze_always_on 0"/>
         <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
         <option name="run-command" value="settings put system show_touches 1"/>
         <option name="run-command" value="settings put system pointer_location 1"/>
@@ -107,4 +109,11 @@
         <option name="collect-on-run-ended-only" value="true"/>
         <option name="clean-up" value="true"/>
     </metrics_collector>
+    <!-- Enable mocking GPS location by the test app -->
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command"
+            value="appops set com.android.shell android:mock_location allow"/>
+        <option name="teardown-command"
+            value="appops set com.android.shell android:mock_location deny"/>
+    </target_preparer>
 </configuration>
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml b/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml
index 7505860..34e4e74 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml
@@ -48,6 +48,8 @@
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="test-user-token" value="%TEST_USER%"/>
         <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
+        <!-- Disable AOD -->
+        <option name="run-command" value="settings put secure doze_always_on 0"/>
         <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
         <option name="run-command" value="settings put system show_touches 1"/>
         <option name="run-command" value="settings put system pointer_location 1"/>
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
index fd4328d..609a284 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -27,6 +27,7 @@
 import android.tools.flicker.subject.exceptions.ExceptionMessageBuilder
 import android.tools.flicker.subject.exceptions.IncorrectRegionException
 import android.tools.flicker.subject.layers.LayerSubject
+import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.EnterPipTransition
 import org.junit.Assume
@@ -65,6 +66,8 @@
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 open class AutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) {
+    override val pipApp: PipAppHelper = PipAppHelper(instrumentation)
+
     override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } }
 
     override val defaultEnterPip: FlickerBuilder.() -> Unit = {
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt
index d4ad4ef8..5698023 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt
@@ -22,6 +22,7 @@
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
 import android.tools.traces.component.ComponentNameMatcher
+import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.wm.shell.Flags
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -57,6 +58,8 @@
 @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class AutoEnterPipWithSourceRectHintTest(flicker: LegacyFlickerTest) :
     AutoEnterPipOnGoToHomeTest(flicker) {
+    override val pipApp: PipAppHelper = PipAppHelper(instrumentation)
+
     override val defaultEnterPip: FlickerBuilder.() -> Unit = {
         setup {
             pipApp.launchViaIntent(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
index 53725fa..880e4cd 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
@@ -21,6 +21,7 @@
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
+import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.ClosePipTransition
 import org.junit.FixMethodOrder
@@ -56,6 +57,8 @@
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class ClosePipWithDismissButtonTest(flicker: LegacyFlickerTest) : ClosePipTransition(flicker) {
+    override val pipApp: PipAppHelper = PipAppHelper(instrumentation)
+
     override val thisTransition: FlickerBuilder.() -> Unit = {
         transitions { pipApp.closePipWindow(wmHelper) }
     }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
index a1551b7..4399a23 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
@@ -21,6 +21,7 @@
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
+import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.EnterPipTransition
 import org.junit.Assume
@@ -47,6 +48,7 @@
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class EnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) {
+    override val pipApp: PipAppHelper = PipAppHelper(instrumentation)
     override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } }
 
     override val defaultEnterPip: FlickerBuilder.() -> Unit = {
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
index ea5b3e5..49efd1d 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
@@ -31,6 +31,7 @@
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.entireScreenCovered
 import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper
+import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.server.wm.flicker.testapp.ActivityOptions.Pip.ACTION_ENTER_PIP
 import com.android.server.wm.flicker.testapp.ActivityOptions.PortraitOnlyActivity.EXTRA_FIXED_ORIENTATION
 import com.android.wm.shell.Flags
@@ -72,6 +73,7 @@
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(flicker) {
+    override val pipApp: PipAppHelper = PipAppHelper(instrumentation)
     private val testApp = FixedOrientationAppHelper(instrumentation)
     private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90)
     private val endingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
index a109c4b..97cc9d2 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
@@ -20,6 +20,7 @@
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
+import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.EnterPipTransition
 import org.junit.FixMethodOrder
@@ -53,6 +54,8 @@
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 open class EnterPipViaAppUiButtonTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) {
+    override val pipApp: PipAppHelper = PipAppHelper(instrumentation)
+
     override val thisTransition: FlickerBuilder.() -> Unit = {
         transitions { pipApp.clickEnterPipButton(wmHelper) }
     }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
index 14ec303..b5b7847 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
@@ -20,6 +20,7 @@
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
+import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition
 import org.junit.FixMethodOrder
@@ -56,6 +57,8 @@
 @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class ExitPipToAppViaExpandButtonTest(flicker: LegacyFlickerTest) :
     ExitPipToAppTransition(flicker) {
+    override val pipApp: PipAppHelper = PipAppHelper(instrumentation)
+
     override val thisTransition: FlickerBuilder.() -> Unit = {
         setup {
             // launch an app behind the pip one
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
index 8a34b5e..f9a9df4 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
@@ -20,6 +20,7 @@
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
+import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition
 import org.junit.FixMethodOrder
@@ -54,6 +55,8 @@
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class ExitPipToAppViaIntentTest(flicker: LegacyFlickerTest) : ExitPipToAppTransition(flicker) {
+    override val pipApp: PipAppHelper = PipAppHelper(instrumentation)
+
     override val thisTransition: FlickerBuilder.() -> Unit = {
         setup {
             // launch an app behind the pip one
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
index 12e2328..79e2e4e 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
@@ -27,6 +27,7 @@
 import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import android.tools.helpers.WindowUtils
 import android.tools.traces.parsers.toFlickerComponent
+import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.testapp.ActivityOptions
 import com.android.wm.shell.Flags
@@ -68,6 +69,7 @@
 @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class FromSplitScreenEnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) :
     EnterPipTransition(flicker) {
+    override val pipApp: PipAppHelper = PipAppHelper(instrumentation)
     private val portraitDisplayBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
     /** Second app used to enter split screen mode */
     private val secondAppForSplitScreen =
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
index 04016a9..14ae93a 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
@@ -23,6 +23,7 @@
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
 import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
@@ -37,6 +38,8 @@
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class PipAspectRatioChangeTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
+    override val pipApp: PipAppHelper = PipAppHelper(instrumentation)
+
     override val thisTransition: FlickerBuilder.() -> Unit = {
         transitions { pipApp.changeAspectRatio(wmHelper) }
     }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
index 6bcaabc..81162c6 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
@@ -49,7 +49,8 @@
         val stringExtras = mapOf(ActivityOptions.Pip.EXTRA_ENTER_PIP to "true")
         setup {
             tapl.setEnableRotation(true)
-            pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras)
+            pipApp.launchViaIntent(wmHelper, stringExtras = stringExtras)
+            pipApp.waitForPip(wmHelper)
 
             // determine the direction of dragging to test for
             isDraggedLeft = pipApp.isCloserToRightEdge(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
index d82bfdd..6118d73 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
@@ -59,7 +59,8 @@
                 // Launch the PIP activity and wait for it to enter PiP mode
                 setRotation(Rotation.ROTATION_0)
                 RemoveAllTasksButHomeRule.removeAllTasksButHome()
-                pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras)
+                pipApp.launchViaIntent(wmHelper, stringExtras = stringExtras)
+                pipApp.waitForPip(wmHelper)
 
                 // get the initial region bounds and cache them
                 val initRegion = pipApp.getWindowRect(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
index dbc97d0..61c59cc 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
@@ -25,6 +25,7 @@
 import android.tools.flicker.legacy.LegacyFlickerTest
 import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import android.tools.flicker.subject.exceptions.IncorrectRegionException
+import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
@@ -40,6 +41,8 @@
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class PipPinchInTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
+    override val pipApp: PipAppHelper = PipAppHelper(instrumentation)
+
     override val thisTransition: FlickerBuilder.() -> Unit = {
         transitions { pipApp.pinchInPipWindow(wmHelper, 0.4f, 30) }
     }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt
index 65b60ce..0867f65 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt
@@ -18,7 +18,6 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.tools.Rotation
-import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.flicker.junit.FlickerBuilderProvider
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
@@ -29,8 +28,6 @@
 import org.junit.runners.Parameterized
 
 abstract class AppsEnterPipTransition(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) {
-    protected abstract val standardAppHelper: StandardAppHelper
-
     protected abstract val permissions: Array<String>
 
     @FlickerBuilderProvider
@@ -39,7 +36,7 @@
             instrumentation.uiAutomation.adoptShellPermissionIdentity()
             for (permission in permissions) {
                 instrumentation.uiAutomation.grantRuntimePermission(
-                    standardAppHelper.packageName,
+                    pipApp.packageName,
                     permission
                 )
             }
@@ -48,18 +45,18 @@
         }
     }
 
-    /** Checks [standardAppHelper] window remains visible throughout the animation */
+    /** Checks [pipApp] window remains visible throughout the animation */
     @Postsubmit
     @Test
     override fun pipAppWindowAlwaysVisible() {
-        flicker.assertWm { this.isAppWindowVisible(standardAppHelper.packageNameMatcher) }
+        flicker.assertWm { this.isAppWindowVisible(pipApp.packageNameMatcher) }
     }
 
-    /** Checks [standardAppHelper] layer remains visible throughout the animation */
+    /** Checks [pipApp] layer remains visible throughout the animation */
     @Postsubmit
     @Test
     override fun pipAppLayerAlwaysVisible() {
-        flicker.assertLayers { this.isVisible(standardAppHelper.packageNameMatcher) }
+        flicker.assertLayers { this.isVisible(pipApp.packageNameMatcher) }
     }
 
     /** Checks the content overlay appears then disappears during the animation */
@@ -70,39 +67,39 @@
     }
 
     /**
-     * Checks that [standardAppHelper] window remains inside the display bounds throughout the whole
+     * Checks that [pipApp] window remains inside the display bounds throughout the whole
      * animation
      */
     @Postsubmit
     @Test
     override fun pipWindowRemainInsideVisibleBounds() {
-        flicker.assertWmVisibleRegion(standardAppHelper.packageNameMatcher) {
+        flicker.assertWmVisibleRegion(pipApp.packageNameMatcher) {
             coversAtMost(displayBounds)
         }
     }
 
     /**
-     * Checks that the [standardAppHelper] layer remains inside the display bounds throughout the
+     * Checks that the [pipApp] layer remains inside the display bounds throughout the
      * whole animation
      */
     @Postsubmit
     @Test
     override fun pipLayerOrOverlayRemainInsideVisibleBounds() {
         flicker.assertLayersVisibleRegion(
-            standardAppHelper.packageNameMatcher.or(ComponentNameMatcher.PIP_CONTENT_OVERLAY)
+            pipApp.packageNameMatcher.or(ComponentNameMatcher.PIP_CONTENT_OVERLAY)
         ) {
             coversAtMost(displayBounds)
         }
     }
 
-    /** Checks that the visible region of [standardAppHelper] always reduces during the animation */
+    /** Checks that the visible region of [pipApp] always reduces during the animation */
     @Postsubmit
     @Test
     override fun pipLayerReduces() {
         flicker.assertLayers {
             val pipLayerList =
                 this.layers {
-                    standardAppHelper.packageNameMatcher.layerMatchesAnyOf(it) && it.isVisible
+                    pipApp.packageNameMatcher.layerMatchesAnyOf(it) && it.isVisible
                 }
             pipLayerList.zipWithNext { previous, current ->
                 current.visibleRegion.notBiggerThan(previous.visibleRegion.region)
@@ -110,14 +107,14 @@
         }
     }
 
-    /** Checks that [standardAppHelper] window becomes pinned */
+    /** Checks that [pipApp] window becomes pinned */
     @Postsubmit
     @Test
     override fun pipWindowBecomesPinned() {
         flicker.assertWm {
-            invoke("pipWindowIsNotPinned") { it.isNotPinned(standardAppHelper.packageNameMatcher) }
+            invoke("pipWindowIsNotPinned") { it.isNotPinned(pipApp.packageNameMatcher) }
                 .then()
-                .invoke("pipWindowIsPinned") { it.isPinned(standardAppHelper.packageNameMatcher) }
+                .invoke("pipWindowIsPinned") { it.isPinned(pipApp.packageNameMatcher) }
         }
     }
 
@@ -129,14 +126,14 @@
     }
 
     /**
-     * Checks that the focus changes between the [standardAppHelper] window and the launcher when
+     * Checks that the focus changes between the [pipApp] window and the launcher when
      * closing the pip window
      */
     @Postsubmit
     @Test
     override fun focusChanges() {
         flicker.assertEventLog {
-            this.focusChanges(standardAppHelper.packageName, "NexusLauncherActivity")
+            this.focusChanges(pipApp.packageName, "NexusLauncherActivity")
         }
     }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt
index 7b04b76..651c923 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt
@@ -29,6 +29,8 @@
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS
+import android.tools.traces.component.ComponentRegexMatcher
 import androidx.test.filters.RequiresDevice
 import org.junit.Assume
 import org.junit.FixMethodOrder
@@ -63,7 +65,7 @@
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 open class MapsEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransition(flicker) {
-    override val standardAppHelper: MapsAppHelper = MapsAppHelper(instrumentation)
+    override val pipApp: MapsAppHelper = MapsAppHelper(instrumentation)
 
     override val permissions: Array<String> =
         arrayOf(Manifest.permission.POST_NOTIFICATIONS, Manifest.permission.ACCESS_FINE_LOCATION)
@@ -110,23 +112,23 @@
 
             // normal app open through the Launcher All Apps
             // var mapsAddressOption = "Golden Gate Bridge"
-            // standardAppHelper.open()
-            // standardAppHelper.doSearch(mapsAddressOption)
-            // standardAppHelper.getDirections()
-            // standardAppHelper.startNavigation();
+            // pipApp.open()
+            // pipApp.doSearch(mapsAddressOption)
+            // pipApp.getDirections()
+            // pipApp.startNavigation();
 
-            standardAppHelper.launchViaIntent(
+            pipApp.launchViaIntent(
                 wmHelper,
                 MapsAppHelper.getMapIntent(MapsAppHelper.INTENT_NAVIGATION)
             )
 
-            standardAppHelper.waitForNavigationToStart()
+            pipApp.waitForNavigationToStart()
         }
     }
 
     override val defaultTeardown: FlickerBuilder.() -> Unit = {
         teardown {
-            standardAppHelper.exit(wmHelper)
+            pipApp.exit(wmHelper)
             mainHandler.removeCallbacks(updateLocation)
             // the main looper callback might have tried to provide a new location after the
             // provider is no longer in test mode, causing a crash, this prevents it from happening
@@ -137,14 +139,14 @@
 
     override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } }
 
-    /** Checks [standardAppHelper] layer remains visible throughout the animation */
+    /** Checks [pipApp] layer remains visible throughout the animation */
     @Postsubmit
     @Test
     override fun pipAppLayerAlwaysVisible() {
         // For Maps the transition goes through the UI mode change that adds a snapshot overlay so
         // we assert only start/end layers matching the app instead.
-        flicker.assertLayersStart { this.isVisible(standardAppHelper.packageNameMatcher) }
-        flicker.assertLayersEnd { this.isVisible(standardAppHelper.packageNameMatcher) }
+        flicker.assertLayersStart { this.isVisible(pipApp.packageNameMatcher) }
+        flicker.assertLayersEnd { this.isVisible(pipApp.packageNameMatcher) }
     }
 
     @Postsubmit
@@ -154,4 +156,15 @@
         Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
         super.focusChanges()
     }
+
+    @Postsubmit
+    @Test
+    override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+        flicker.assertLayers {
+            this.visibleLayersShownMoreThanOneConsecutiveEntry(
+                ignoreLayers = VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS
+                    + ComponentRegexMatcher(Regex("Background for .* SurfaceView\\[com\\.google\\.android\\.apps\\.maps/com\\.google\\.android\\.maps\\.MapsActivity\\]\\#\\d+"))
+            )
+        }
+    }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt
index 6911946..be4cd78 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt
@@ -61,7 +61,7 @@
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 open class NetflixEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransition(flicker) {
-    override val standardAppHelper: NetflixAppHelper = NetflixAppHelper(instrumentation)
+    override val pipApp: NetflixAppHelper = NetflixAppHelper(instrumentation)
     private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90)
     private val endingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
 
@@ -69,17 +69,17 @@
 
     override val defaultEnterPip: FlickerBuilder.() -> Unit = {
         setup {
-            standardAppHelper.launchViaIntent(
+            pipApp.launchViaIntent(
                 wmHelper,
                 NetflixAppHelper.getNetflixWatchVideoIntent("81605060"),
                 ComponentNameMatcher(NetflixAppHelper.PACKAGE_NAME, NetflixAppHelper.WATCH_ACTIVITY)
             )
-            standardAppHelper.waitForVideoPlaying()
+            pipApp.waitForVideoPlaying()
         }
     }
 
     override val defaultTeardown: FlickerBuilder.() -> Unit = {
-        teardown { standardAppHelper.exit(wmHelper) }
+        teardown { pipApp.exit(wmHelper) }
     }
 
     override val thisTransition: FlickerBuilder.() -> Unit = {
@@ -143,7 +143,7 @@
         // might go outside of bounds as we resize from landscape fullscreen to destination bounds,
         // and once the animation is over we assert that it's fully within the display bounds, at
         // which point the device also performs orientation change from landscape to portrait
-        flicker.assertWmVisibleRegion(standardAppHelper.packageNameMatcher) {
+        flicker.assertWmVisibleRegion(pipApp.packageNameMatcher) {
             regionsCenterPointInside(startingBounds).then().coversAtMost(endingBounds)
         }
     }
@@ -156,7 +156,7 @@
         // and once the animation is over we assert that it's fully within the display bounds, at
         // which point the device also performs orientation change from landscape to portrait
         // since Netflix uses source rect hint, there is no PiP overlay present
-        flicker.assertLayersVisibleRegion(standardAppHelper.packageNameMatcher) {
+        flicker.assertLayersVisibleRegion(pipApp.packageNameMatcher) {
             regionsCenterPointInside(startingBounds).then().coversAtMost(endingBounds)
         }
     }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt
index 5e54f30..3e4ff30 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt
@@ -57,23 +57,23 @@
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 open class YouTubeEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransition(flicker) {
-    override val standardAppHelper: YouTubeAppHelper = YouTubeAppHelper(instrumentation)
+    override val pipApp: YouTubeAppHelper = YouTubeAppHelper(instrumentation)
 
     override val permissions: Array<String> = arrayOf(Manifest.permission.POST_NOTIFICATIONS)
 
     override val defaultEnterPip: FlickerBuilder.() -> Unit = {
         setup {
-            standardAppHelper.launchViaIntent(
+            pipApp.launchViaIntent(
                 wmHelper,
                 YouTubeAppHelper.getYoutubeVideoIntent("3KtWfp0UopM"),
                 ComponentNameMatcher(YouTubeAppHelper.PACKAGE_NAME, "")
             )
-            standardAppHelper.waitForVideoPlaying()
+            pipApp.waitForVideoPlaying()
         }
     }
 
     override val defaultTeardown: FlickerBuilder.() -> Unit = {
-        teardown { standardAppHelper.exit(wmHelper) }
+        teardown { pipApp.exit(wmHelper) }
     }
 
     override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt
index 159cba4..2c6cb503 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt
@@ -63,7 +63,7 @@
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 open class YouTubeEnterPipToOtherOrientationTest(flicker: LegacyFlickerTest) :
     YouTubeEnterPipTest(flicker) {
-    override val standardAppHelper: YouTubeAppHelper = YouTubeAppHelper(instrumentation)
+    override val pipApp: YouTubeAppHelper = YouTubeAppHelper(instrumentation)
     private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90)
     private val endingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
 
@@ -71,13 +71,13 @@
 
     override val defaultEnterPip: FlickerBuilder.() -> Unit = {
         setup {
-            standardAppHelper.launchViaIntent(
+            pipApp.launchViaIntent(
                 wmHelper,
                 YouTubeAppHelper.getYoutubeVideoIntent("3KtWfp0UopM"),
                 ComponentNameMatcher(YouTubeAppHelper.PACKAGE_NAME, "")
             )
-            standardAppHelper.enterFullscreen()
-            standardAppHelper.waitForVideoPlaying()
+            pipApp.enterFullscreen()
+            pipApp.waitForVideoPlaying()
         }
     }
 
@@ -101,7 +101,7 @@
         // might go outside of bounds as we resize from landscape fullscreen to destination bounds,
         // and once the animation is over we assert that it's fully within the display bounds, at
         // which point the device also performs orientation change from landscape to portrait
-        flicker.assertWmVisibleRegion(standardAppHelper.packageNameMatcher) {
+        flicker.assertWmVisibleRegion(pipApp.packageNameMatcher) {
             regionsCenterPointInside(startingBounds).then().coversAtMost(endingBounds)
         }
     }
@@ -114,7 +114,7 @@
         // and once the animation is over we assert that it's fully within the display bounds, at
         // which point the device also performs orientation change from landscape to portrait
         // since YouTube uses source rect hint, there is no PiP overlay present
-        flicker.assertLayersVisibleRegion(standardAppHelper.packageNameMatcher) {
+        flicker.assertLayersVisibleRegion(pipApp.packageNameMatcher) {
             regionsCenterPointInside(startingBounds).then().coversAtMost(endingBounds)
         }
     }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt
index 6dd3a17..a72de0f 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt
@@ -71,7 +71,9 @@
     @Presubmit
     @Test
     open fun pipLayerOrOverlayRemainInsideVisibleBounds() {
-        flicker.assertLayersVisibleRegion(pipApp.or(ComponentNameMatcher.PIP_CONTENT_OVERLAY)) {
+        flicker.assertLayersVisibleRegion(
+            pipApp.or(ComponentNameMatcher.PIP_CONTENT_OVERLAY)
+        ) {
             coversAtMost(displayBounds)
         }
     }
@@ -117,7 +119,9 @@
     @Presubmit
     @Test
     open fun focusChanges() {
-        flicker.assertEventLog { this.focusChanges(pipApp.packageName, "NexusLauncherActivity") }
+        flicker.assertEventLog {
+            this.focusChanges(pipApp.packageName, "NexusLauncherActivity")
+        }
     }
 
     companion object {
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
index c37bf35..7b6625d 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
@@ -27,6 +27,7 @@
 import android.tools.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
 import android.tools.helpers.WindowUtils
 import android.tools.traces.component.ComponentNameMatcher
+import android.tools.device.apphelpers.PipApp
 import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.testapp.ActivityOptions
@@ -40,7 +41,6 @@
     @Rule
     val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
 
-    protected val pipApp = PipAppHelper(instrumentation)
     protected val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.startRotation)
     protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation)
 
@@ -63,6 +63,11 @@
         }
     }
 
+    /**
+     * Defines the test app to run PIP flicker test.
+     */
+    protected open val pipApp: PipApp = PipAppHelper(instrumentation)
+
     /** Defines the transition used to run the test */
     protected open val thisTransition: FlickerBuilder.() -> Unit = {}
 
@@ -85,10 +90,11 @@
     /** Defines the default method of entering PiP */
     protected open val defaultEnterPip: FlickerBuilder.() -> Unit = {
         setup {
-            pipApp.launchViaIntentAndWaitForPip(
+            pipApp.launchViaIntent(
                 wmHelper,
                 stringExtras = mapOf(ActivityOptions.Pip.EXTRA_ENTER_PIP to "true")
             )
+            pipApp.waitForPip(wmHelper)
         }
     }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt
index c4954f9..feb3edc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt
@@ -20,6 +20,7 @@
 import android.graphics.Point
 import android.os.SystemClock
 import android.tools.Rotation
+import android.tools.device.apphelpers.IStandardAppHelper
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.flicker.rules.ChangeDisplayOrientationRule
 import android.tools.traces.component.ComponentNameMatcher
@@ -102,8 +103,8 @@
         wmHelper: WindowManagerStateHelper,
         tapl: LauncherInstrumentation,
         device: UiDevice,
-        primaryApp: StandardAppHelper,
-        secondaryApp: StandardAppHelper,
+        primaryApp: IStandardAppHelper,
+        secondaryApp: IStandardAppHelper,
         rotation: Rotation
     ) {
         primaryApp.launchViaIntent(wmHelper)
@@ -117,8 +118,8 @@
 
     fun enterSplitViaIntent(
         wmHelper: WindowManagerStateHelper,
-        primaryApp: StandardAppHelper,
-        secondaryApp: StandardAppHelper
+        primaryApp: IStandardAppHelper,
+        secondaryApp: IStandardAppHelper
     ) {
         val stringExtras = mapOf(Primary.EXTRA_LAUNCH_ADJACENT to "true")
         primaryApp.launchViaIntent(wmHelper, null, null, stringExtras)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java
index 9c31b46..310c2d7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java
@@ -26,6 +26,7 @@
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.WindowConfiguration;
+import android.content.ComponentName;
 import android.content.Intent;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -42,7 +43,9 @@
     private int mParentTaskId = INVALID_TASK_ID;
     private int mUid = INVALID_TASK_ID;
     private int mTaskId = INVALID_TASK_ID;
+    private int mUserId = -1;
     private Intent mBaseIntent = new Intent();
+    private ComponentName mBaseActivity = null;
     private @WindowConfiguration.ActivityType int mActivityType = ACTIVITY_TYPE_STANDARD;
     private @WindowConfiguration.WindowingMode int mWindowingMode = WINDOWING_MODE_UNDEFINED;
     private @WindowConfiguration.ActivityType int mTopActivityType = ACTIVITY_TYPE_STANDARD;
@@ -88,6 +91,12 @@
         return this;
     }
 
+    /** Sets the task info's user id. */
+    public TestRunningTaskInfoBuilder setUserId(int userId) {
+        mUserId = userId;
+        return this;
+    }
+
     /**
      * Set {@link ActivityManager.RunningTaskInfo#baseIntent} for the task info, by default
      * an empty intent is assigned
@@ -97,6 +106,14 @@
         return this;
     }
 
+    /**
+     * Set {@link ActivityManager.RunningTaskInfo#baseActivity} for the task info.
+     */
+    public TestRunningTaskInfoBuilder setBaseActivity(@NonNull ComponentName activity) {
+        mBaseActivity = activity;
+        return this;
+    }
+
     public TestRunningTaskInfoBuilder setActivityType(
             @WindowConfiguration.ActivityType int activityType) {
         mActivityType = activityType;
@@ -172,6 +189,8 @@
         info.isTopActivityTransparent = mIsTopActivityTransparent;
         info.numActivities = mNumActivities;
         info.lastActiveTime = mLastActiveTime;
+        info.userId = mUserId;
+        info.baseActivity = mBaseActivity;
         return info;
     }
 }
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 13a8518..c3e3965 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
@@ -57,6 +57,8 @@
 import android.os.IBinder;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableContentResolver;
@@ -91,6 +93,7 @@
 import com.android.wm.shell.transition.Transitions;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -140,6 +143,8 @@
     private RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
     @Mock
     private Handler mHandler;
+    @Mock
+    private Transitions.TransitionHandler mTakeoverHandler;
 
     private BackAnimationController mController;
     private TestableContentResolver mContentResolver;
@@ -152,6 +157,9 @@
 
     private BackAnimationController.BackTransitionHandler mBackTransitionHandler;
 
+    @Rule
+    public SetFlagsRule mSetflagsRule = new SetFlagsRule();
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
@@ -605,6 +613,51 @@
         verify(mAnimatorCallback, never()).onBackInvoked();
     }
 
+    @EnableFlags({com.android.systemui.shared.Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+            com.android.systemui.shared.Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
+            com.android.window.flags.Flags.FLAG_UNIFY_BACK_NAVIGATION_TRANSITION})
+    @Test
+    public void appCallback_receivesTakeoverHandler_whenAvailable() throws RemoteException {
+        registerAnimation(BackNavigationInfo.TYPE_CROSS_TASK);
+        mBackTransitionHandler.mTakeoverHandler = mTakeoverHandler;
+
+        final int type = BackNavigationInfo.TYPE_CALLBACK;
+        final ResultListener result = new ResultListener();
+        createNavigationInfo(new BackNavigationInfo.Builder()
+                .setType(type)
+                .setOnBackInvokedCallback(mAppCallback)
+                .setOnBackNavigationDone(new RemoteCallback(result))
+                .setTouchableRegion(mTouchableRegion)
+                .setAppProgressAllowed(true));
+
+        triggerBackGesture();
+        mShellExecutor.flushAll();
+        releaseBackGesture();
+        mShellExecutor.flushAll();
+
+        verify(mAppCallback).setHandoffHandler(any());
+    }
+
+    @Test
+    public void appCallback_doesNotReceiveTakeoverHandler_whenUnavailable() throws RemoteException {
+        registerAnimation(BackNavigationInfo.TYPE_CROSS_TASK);
+
+        final int type = BackNavigationInfo.TYPE_CALLBACK;
+        final ResultListener result = new ResultListener();
+        createNavigationInfo(new BackNavigationInfo.Builder()
+                .setType(type)
+                .setOnBackInvokedCallback(mAppCallback)
+                .setOnBackNavigationDone(new RemoteCallback(result))
+                .setTouchableRegion(mTouchableRegion)
+                .setAppProgressAllowed(true));
+        triggerBackGesture();
+        mShellExecutor.flushAll();
+        releaseBackGesture();
+        mShellExecutor.flushAll();
+
+        verify(mAppCallback, never()).setHandoffHandler(any());
+    }
+
     @Test
     public void skipsCancelWithoutStart() throws RemoteException {
         final int type = BackNavigationInfo.TYPE_CALLBACK;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
index 0373bbd..6f3a3ec 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
@@ -172,10 +172,10 @@
         var mockPp = mock(DisplayImeController.ImePositionProcessor.class);
         mDisplayImeController.addPositionProcessor(mockPp);
 
-        mPerDisplay.setImeInputTargetRequestedVisibility(true);
+        mPerDisplay.setImeInputTargetRequestedVisibility(true, null /* statsToken */);
         verify(mockPp).onImeRequested(anyInt(), eq(true));
 
-        mPerDisplay.setImeInputTargetRequestedVisibility(false);
+        mPerDisplay.setImeInputTargetRequestedVisibility(false, null /* statsToken */);
         verify(mockPp).onImeRequested(anyInt(), eq(false));
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/transition/TransitionStateHolderTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/transition/TransitionStateHolderTest.kt
new file mode 100644
index 0000000..64772d0
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/transition/TransitionStateHolderTest.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright 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.common.transition
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.TestShellExecutor
+import com.android.wm.shell.recents.RecentsTransitionHandler
+import com.android.wm.shell.recents.RecentsTransitionStateListener
+import com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_ANIMATING
+import com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_NOT_RUNNING
+import com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_REQUESTED
+import com.android.wm.shell.sysui.ShellInit
+import kotlin.test.assertNotNull
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.any
+import org.mockito.kotlin.never
+
+/**
+ * Test class for {@link TransitionStateHolder}
+ *
+ * Usage: atest WMShellUnitTests:TransitionStateHolderTest
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class TransitionStateHolderTest {
+
+    lateinit var recentTransitionHandler: RecentsTransitionHandler
+    lateinit var shellInit: ShellInit
+
+    @Before
+    fun before() {
+        recentTransitionHandler = mock(RecentsTransitionHandler::class.java)
+        shellInit = ShellInit(TestShellExecutor())
+    }
+
+    @Test
+    fun `No TransitionStateHolder listeners before initialization`() {
+        TransitionStateHolder(shellInit, recentTransitionHandler)
+        verify(recentTransitionHandler, never()).addTransitionStateListener(any())
+    }
+
+    @Test
+    fun `When TransitionStateHolder initialized a listener has been registered `() {
+        TransitionStateHolder(shellInit, recentTransitionHandler)
+        shellInit.init()
+        assertNotNull(recentsTransitionStateListener)
+    }
+
+    @Test
+    fun `When TransitionStateHolder is created  no recent animation running`() {
+        val holder = TransitionStateHolder(shellInit, recentTransitionHandler)
+        shellInit.init()
+        assertFalse(holder.isRecentsTransitionRunning())
+    }
+
+    @Test
+    fun `Recent animation running updates after callback value`() {
+        val holder = TransitionStateHolder(shellInit, recentTransitionHandler)
+        shellInit.init()
+
+        assertFalse(holder.isRecentsTransitionRunning())
+
+        recentsTransitionStateListener.onTransitionStateChanged(TRANSITION_STATE_NOT_RUNNING)
+        assertFalse(holder.isRecentsTransitionRunning())
+
+        recentsTransitionStateListener.onTransitionStateChanged(TRANSITION_STATE_REQUESTED)
+        assertTrue(holder.isRecentsTransitionRunning())
+
+        recentsTransitionStateListener.onTransitionStateChanged(TRANSITION_STATE_ANIMATING)
+        assertTrue(holder.isRecentsTransitionRunning())
+    }
+
+    private val recentsTransitionStateListener: RecentsTransitionStateListener
+        get() = ArgumentCaptor.forClass(RecentsTransitionStateListener::class.java).run {
+            verify(recentTransitionHandler).addTransitionStateListener(capture())
+            value
+        }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt
index 803e5d4..1d39000 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt
@@ -21,7 +21,7 @@
 import androidx.test.filters.SmallTest
 import com.android.internal.R
 import com.android.wm.shell.ShellTestCase
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
 import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
index d5287e7..67573da 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
@@ -30,6 +30,7 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.TaskInfo;
@@ -61,12 +62,16 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.compatui.api.CompatUIInfo;
+import com.android.wm.shell.desktopmode.DesktopRepository;
+import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
 
 import dagger.Lazy;
 
+import java.util.Optional;
+
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
@@ -130,6 +135,10 @@
     private CompatUIShellCommandHandler mCompatUIShellCommandHandler;
     @Mock
     private AccessibilityManager mAccessibilityManager;
+    @Mock
+    private DesktopUserRepositories mDesktopUserRepositories;
+    @Mock
+    private DesktopRepository mDesktopRepository;
 
     @Captor
     ArgumentCaptor<OnInsetsChangedListener> mOnInsetsChangedListenerCaptor;
@@ -137,7 +146,6 @@
     @NonNull
     private CompatUIStatusManager mCompatUIStatusManager;
 
-    private boolean mInDesktopModePredicateResult;
 
     @Before
     public void setUp() {
@@ -152,6 +160,8 @@
         doReturn(TASK_ID).when(mMockLetterboxEduLayout).getTaskId();
         doReturn(true).when(mMockLetterboxEduLayout).createLayout(anyBoolean());
         doReturn(true).when(mMockLetterboxEduLayout).updateCompatInfo(any(), any(), anyBoolean());
+        doReturn(mDesktopRepository).when(mDesktopUserRepositories).getCurrent();
+        doReturn(mDesktopRepository).when(mDesktopUserRepositories).getProfile(anyInt());
 
         doReturn(DISPLAY_ID).when(mMockRestartDialogLayout).getDisplayId();
         doReturn(TASK_ID).when(mMockRestartDialogLayout).getTaskId();
@@ -164,7 +174,7 @@
                 mMockDisplayController, mMockDisplayInsetsController, mMockImeController,
                 mMockSyncQueue, mMockExecutor, mMockTransitionsLazy, mDockStateReader,
                 mCompatUIConfiguration, mCompatUIShellCommandHandler, mAccessibilityManager,
-                mCompatUIStatusManager, i -> mInDesktopModePredicateResult) {
+                mCompatUIStatusManager, Optional.of(mDesktopUserRepositories)) {
             @Override
             CompatUIWindowManager createCompatUiWindowManager(Context context, TaskInfo taskInfo,
                     ShellTaskOrganizer.TaskListener taskListener) {
@@ -707,13 +717,17 @@
     @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK)
     @EnableFlags(Flags.FLAG_SKIP_COMPAT_UI_EDUCATION_IN_DESKTOP_MODE)
     public void testUpdateActiveTaskInfo_removeAllComponentWhenInDesktopModeFlagEnabled() {
-        mInDesktopModePredicateResult = false;
         TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true);
+        when(mDesktopUserRepositories.getCurrent().getVisibleTaskCount(DISPLAY_ID)).thenReturn(0);
+
         mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener));
+
         verify(mController, never()).removeLayouts(taskInfo.taskId);
 
-        mInDesktopModePredicateResult = true;
+        when(mDesktopUserRepositories.getCurrent().getVisibleTaskCount(DISPLAY_ID)).thenReturn(2);
+
         mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener));
+
         verify(mController).removeLayouts(taskInfo.taskId);
     }
 
@@ -721,13 +735,17 @@
     @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK)
     @DisableFlags(Flags.FLAG_SKIP_COMPAT_UI_EDUCATION_IN_DESKTOP_MODE)
     public void testUpdateActiveTaskInfo_removeAllComponentWhenInDesktopModeFlagDisabled() {
-        mInDesktopModePredicateResult = false;
+        when(mDesktopUserRepositories.getCurrent().getVisibleTaskCount(DISPLAY_ID)).thenReturn(0);
         TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true);
+
         mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener));
+
         verify(mController, never()).removeLayouts(taskInfo.taskId);
 
-        mInDesktopModePredicateResult = true;
+        when(mDesktopUserRepositories.getCurrent().getVisibleTaskCount(DISPLAY_ID)).thenReturn(2);
+
         mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener));
+
         verify(mController, never()).removeLayouts(taskInfo.taskId);
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxSurfaceBuilderTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxSurfaceBuilderTest.kt
new file mode 100644
index 0000000..68d9bf9
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxSurfaceBuilderTest.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright 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.compatui.letterbox
+
+import android.content.Context
+import android.testing.AndroidTestingRunner
+import android.view.SurfaceControl
+import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn
+import com.android.wm.shell.ShellTestCase
+import java.util.function.Consumer
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.never
+import org.mockito.kotlin.times
+import org.mockito.verification.VerificationMode
+
+/**
+ * Tests for [LetterboxSurfaceBuilder].
+ *
+ * Build/Install/Run:
+ *  atest WMShellUnitTests:LetterboxSurfaceBuilderTest
+ */
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class LetterboxSurfaceBuilderTest : ShellTestCase() {
+
+    @Test
+    fun `When surface is created mandatory methods are invoked`() {
+        runTestScenario { r ->
+            r.invokeBuilder()
+
+            r.checkNameIsSet(expected = true)
+            r.checkCallSiteIsSet(expected = true)
+            r.checkSurfaceIsHidden(invoked = true, isHidden = true)
+            r.checkColorLayerIsSet(expected = true)
+            r.checkParentLeashIsSet(expected = true)
+            r.checkSetLayerIsInvoked(expected = true)
+            r.checkColorSpaceAgnosticIsSet(expected = true, value = true)
+            r.checkColorIsSetFromLetterboxConfiguration(expected = true)
+        }
+    }
+
+    /**
+     * Runs a test scenario providing a Robot.
+     */
+    fun runTestScenario(consumer: Consumer<LetterboxSurfaceBuilderRobotTest>) {
+        val robot = LetterboxSurfaceBuilderRobotTest(mContext)
+        consumer.accept(robot)
+    }
+
+    class LetterboxSurfaceBuilderRobotTest(val ctx: Context) {
+
+        private val letterboxConfiguration: LetterboxConfiguration
+        private val letterboxSurfaceBuilder: LetterboxSurfaceBuilder
+        private val tx: SurfaceControl.Transaction
+        private val parentLeash: SurfaceControl
+        private val surfaceBuilder: SurfaceControl.Builder
+
+        companion object {
+            @JvmStatic
+            val TEST_SURFACE_NAME = "SurfaceForTest"
+
+            @JvmStatic
+            val TEST_SURFACE_CALL_SITE = "CallSiteForTest"
+        }
+
+        init {
+            letterboxConfiguration = LetterboxConfiguration(ctx)
+            letterboxSurfaceBuilder = LetterboxSurfaceBuilder(letterboxConfiguration)
+            tx = org.mockito.kotlin.mock<SurfaceControl.Transaction>()
+            doReturn(tx).`when`(tx).setLayer(anyOrNull(), anyOrNull())
+            doReturn(tx).`when`(tx).setColorSpaceAgnostic(anyOrNull(), anyOrNull())
+            parentLeash = org.mockito.kotlin.mock<SurfaceControl>()
+            surfaceBuilder = SurfaceControl.Builder()
+            spyOn(surfaceBuilder)
+        }
+
+        fun invokeBuilder() {
+            letterboxSurfaceBuilder.createSurface(
+                tx,
+                parentLeash,
+                TEST_SURFACE_NAME,
+                TEST_SURFACE_CALL_SITE,
+                surfaceBuilder
+            )
+        }
+
+        fun checkNameIsSet(expected: Boolean) {
+            verify(surfaceBuilder, expected.asMode())
+                .setName(TEST_SURFACE_NAME)
+        }
+
+        fun checkCallSiteIsSet(expected: Boolean) {
+            verify(surfaceBuilder, expected.asMode())
+                .setCallsite(TEST_SURFACE_CALL_SITE)
+        }
+
+        fun checkSurfaceIsHidden(invoked: Boolean, isHidden: Boolean) {
+            verify(surfaceBuilder, invoked.asMode())
+                .setHidden(isHidden)
+        }
+
+        fun checkColorLayerIsSet(expected: Boolean) {
+            verify(surfaceBuilder, expected.asMode()).setColorLayer()
+        }
+
+        fun checkParentLeashIsSet(expected: Boolean) {
+            verify(surfaceBuilder, expected.asMode()).setParent(parentLeash)
+        }
+
+        fun checkSetLayerIsInvoked(expected: Boolean) {
+            verify(tx, expected.asMode()).setLayer(anyOrNull(), ArgumentMatchers.anyInt())
+        }
+
+        fun checkColorSpaceAgnosticIsSet(expected: Boolean, value: Boolean) {
+            verify(tx, expected.asMode()).setColorSpaceAgnostic(anyOrNull(), eq(value))
+        }
+
+        fun checkColorIsSetFromLetterboxConfiguration(expected: Boolean) {
+            val components = letterboxConfiguration.getBackgroundColorRgbArray()
+            verify(tx, expected.asMode()).setColor(anyOrNull(), eq(components))
+        }
+
+        private fun Boolean.asMode(): VerificationMode = if (this) times(1) else never()
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserverTest.kt
index 1ae1c3f..07bfefe 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserverTest.kt
@@ -16,15 +16,21 @@
 
 package com.android.wm.shell.compatui.letterbox
 
+import android.graphics.Point
+import android.graphics.Rect
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.SetFlagsRule
 import android.testing.AndroidTestingRunner
+import android.view.SurfaceControl
 import android.view.WindowManager.TRANSIT_CLOSE
 import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn
 import com.android.window.flags.Flags
 import com.android.wm.shell.ShellTestCase
 import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.common.transition.TransitionStateHolder
+import com.android.wm.shell.recents.RecentsTransitionHandler
 import com.android.wm.shell.sysui.ShellInit
 import com.android.wm.shell.transition.Transitions
 import com.android.wm.shell.util.TransitionObserverInputBuilder
@@ -33,12 +39,13 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mockito
 import org.mockito.kotlin.any
+import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
 import org.mockito.kotlin.never
 import org.mockito.kotlin.times
-import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.verify
 import org.mockito.verification.VerificationMode
 
 /**
@@ -93,7 +100,7 @@
                     r.creationEventDetected(expected = false)
                     r.visibilityEventDetected(expected = false)
                     r.destroyEventDetected(expected = false)
-                    r.boundsEventDetected(expected = false)
+                    r.updateSurfaceBoundsEventDetected(expected = false)
                 }
             }
         }
@@ -107,14 +114,23 @@
 
                 inputBuilder {
                     buildTransitionInfo()
-                    r.createTopActivityChange(inputBuilder = this, isLetterboxed = true)
+                    r.createTopActivityChange(
+                        inputBuilder = this,
+                        isLetterboxed = true,
+                        taskPosition = Point(20, 30),
+                        taskWidth = 200,
+                        taskHeight = 300
+                    )
                 }
 
                 validateOutput {
                     r.creationEventDetected(expected = true)
                     r.visibilityEventDetected(expected = true, visible = true)
                     r.destroyEventDetected(expected = false)
-                    r.boundsEventDetected(expected = true)
+                    r.updateSurfaceBoundsEventDetected(
+                        expected = true,
+                        taskBounds = Rect(20, 30, 200, 300)
+                    )
                 }
             }
         }
@@ -135,14 +151,33 @@
                     r.creationEventDetected(expected = false)
                     r.visibilityEventDetected(expected = true, visible = false)
                     r.destroyEventDetected(expected = false)
-                    r.boundsEventDetected(expected = false)
+                    r.updateSurfaceBoundsEventDetected(expected = false)
                 }
             }
         }
     }
 
     @Test
-    fun `When closing change letterbox surface destroy is triggered`() {
+    fun `When closing change with no recents running letterbox surfaces are destroyed`() {
+        runTestScenario { r ->
+            executeTransitionObserverTest(observerFactory = r.observerFactory) {
+                r.invokeShellInit()
+
+                inputBuilder {
+                    buildTransitionInfo()
+                    r.configureRecentsState(running = false)
+                    r.createClosingChange(inputBuilder = this)
+                }
+
+                validateOutput {
+                    r.destroyEventDetected(expected = true)
+                }
+            }
+        }
+    }
+
+    @Test
+    fun `When closing change and recents are running letterbox surfaces are not destroyed`() {
         runTestScenario { r ->
             executeTransitionObserverTest(observerFactory = r.observerFactory) {
                 r.invokeShellInit()
@@ -150,13 +185,11 @@
                 inputBuilder {
                     buildTransitionInfo()
                     r.createClosingChange(inputBuilder = this)
+                    r.configureRecentsState(running = true)
                 }
 
                 validateOutput {
-                    r.destroyEventDetected(expected = true)
-                    r.creationEventDetected(expected = false)
-                    r.visibilityEventDetected(expected = false, visible = false)
-                    r.boundsEventDetected(expected = false)
+                    r.destroyEventDetected(expected = false)
                 }
             }
         }
@@ -185,16 +218,25 @@
         private val transitions: Transitions
         private val letterboxController: LetterboxController
         private val letterboxObserver: LetterboxTransitionObserver
+        private val transitionStateHolder: TransitionStateHolder
 
         val observerFactory: () -> LetterboxTransitionObserver
 
         init {
-            executor = Mockito.mock(ShellExecutor::class.java)
+            executor = mock<ShellExecutor>()
             shellInit = ShellInit(executor)
-            transitions = Mockito.mock(Transitions::class.java)
-            letterboxController = Mockito.mock(LetterboxController::class.java)
+            transitions = mock<Transitions>()
+            letterboxController = mock<LetterboxController>()
+            transitionStateHolder =
+                TransitionStateHolder(shellInit, mock<RecentsTransitionHandler>())
+            spyOn(transitionStateHolder)
             letterboxObserver =
-                LetterboxTransitionObserver(shellInit, transitions, letterboxController)
+                LetterboxTransitionObserver(
+                    shellInit,
+                    transitions,
+                    letterboxController,
+                    transitionStateHolder
+                )
             observerFactory = { letterboxObserver }
         }
 
@@ -203,67 +245,82 @@
         fun observer() = letterboxObserver
 
         fun checkObservableIsRegistered(expected: Boolean) {
-            Mockito.verify(transitions, expected.asMode()).registerObserver(observer())
+            verify(transitions, expected.asMode()).registerObserver(observer())
+        }
+
+        fun configureRecentsState(running: Boolean) {
+            doReturn(running).`when`(transitionStateHolder).isRecentsTransitionRunning()
         }
 
         fun creationEventDetected(
             expected: Boolean,
             displayId: Int = DISPLAY_ID,
             taskId: Int = TASK_ID
-        ) {
-            Mockito.verify(letterboxController, expected.asMode()).createLetterboxSurface(
-                toLetterboxKeyMatcher(displayId, taskId),
-                anyOrNull(),
-                anyOrNull()
-            )
-        }
+        ) = verify(
+            letterboxController,
+            expected.asMode()
+        ).createLetterboxSurface(
+            eq(LetterboxKey(displayId, taskId)),
+            any<SurfaceControl.Transaction>(),
+            any<SurfaceControl>()
+        )
 
         fun visibilityEventDetected(
             expected: Boolean,
+            visible: Boolean = true,
             displayId: Int = DISPLAY_ID,
-            taskId: Int = TASK_ID,
-            visible: Boolean? = null
-        ) {
-            Mockito.verify(letterboxController, expected.asMode()).updateLetterboxSurfaceVisibility(
-                toLetterboxKeyMatcher(displayId, taskId),
-                anyOrNull(),
-                visible.asMatcher()
-            )
-        }
+            taskId: Int = TASK_ID
+        ) = verify(letterboxController, expected.asMode()).updateLetterboxSurfaceVisibility(
+            eq(LetterboxKey(displayId, taskId)),
+            any<SurfaceControl.Transaction>(),
+            eq(visible)
+        )
 
         fun destroyEventDetected(
             expected: Boolean,
             displayId: Int = DISPLAY_ID,
             taskId: Int = TASK_ID
-        ) {
-            Mockito.verify(letterboxController, expected.asMode()).destroyLetterboxSurface(
-                toLetterboxKeyMatcher(displayId, taskId),
-                anyOrNull()
-            )
-        }
+        ) = verify(
+            letterboxController,
+            expected.asMode()
+        ).destroyLetterboxSurface(
+            eq(LetterboxKey(displayId, taskId)),
+            any<SurfaceControl.Transaction>()
+        )
 
-        fun boundsEventDetected(
+        fun updateSurfaceBoundsEventDetected(
             expected: Boolean,
             displayId: Int = DISPLAY_ID,
-            taskId: Int = TASK_ID
-        ) {
-            Mockito.verify(letterboxController, expected.asMode()).updateLetterboxSurfaceBounds(
-                toLetterboxKeyMatcher(displayId, taskId),
-                anyOrNull(),
-                anyOrNull()
-            )
-        }
+            taskId: Int = TASK_ID,
+            taskBounds: Rect = Rect()
+        ) = verify(
+            letterboxController,
+            expected.asMode()
+        ).updateLetterboxSurfaceBounds(
+            eq(LetterboxKey(displayId, taskId)),
+            any<SurfaceControl.Transaction>(),
+            eq(taskBounds)
+        )
 
         fun createTopActivityChange(
             inputBuilder: TransitionObserverInputBuilder,
             isLetterboxed: Boolean = true,
             displayId: Int = DISPLAY_ID,
-            taskId: Int = TASK_ID
+            taskId: Int = TASK_ID,
+            taskPosition: Point = Point(),
+            taskWidth: Int = 0,
+            taskHeight: Int = 0
         ) {
-            inputBuilder.addChange(changeTaskInfo = inputBuilder.createTaskInfo().apply {
-                appCompatTaskInfo.isTopActivityLetterboxed = isLetterboxed
-                this.taskId = taskId
-                this.displayId = displayId
+            inputBuilder.addChange(inputBuilder.createChange(
+                changeTaskInfo = inputBuilder.createTaskInfo().apply {
+                    appCompatTaskInfo.isTopActivityLetterboxed = isLetterboxed
+                    this.taskId = taskId
+                    this.displayId = displayId
+                }
+            ).apply {
+                endRelOffset.x = taskPosition.x
+                endRelOffset.y = taskPosition.y
+                endAbsBounds.set(Rect(0, 0, taskWidth, taskHeight))
             })
         }
 
@@ -279,16 +336,5 @@
         }
 
         private fun Boolean.asMode(): VerificationMode = if (this) times(1) else never()
-
-        private fun Boolean?.asMatcher(): Boolean =
-            if (this != null) eq(this) else any()
-
-        private fun toLetterboxKeyMatcher(displayId: Int, taskId: Int): LetterboxKey {
-            if (displayId < 0 || taskId < 0) {
-                return any()
-            } else {
-                return eq(LetterboxKey(displayId, taskId))
-            }
-        }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt
index aabd973..41a594a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt
@@ -23,6 +23,7 @@
 import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
 import android.graphics.Rect
 import android.os.Binder
+import android.os.UserManager
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.SetFlagsRule
 import android.testing.AndroidTestingRunner
@@ -39,8 +40,8 @@
 import com.android.wm.shell.ShellTestCase
 import com.android.wm.shell.common.ShellExecutor
 import com.android.wm.shell.common.TaskStackListenerImpl
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTask
 import com.android.wm.shell.desktopmode.persistence.Desktop
 import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
 import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer
@@ -96,11 +97,12 @@
     @Mock lateinit var taskStackListener: TaskStackListenerImpl
     @Mock lateinit var persistentRepository: DesktopPersistentRepository
     @Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer
+    @Mock lateinit var userManager: UserManager
 
     private lateinit var mockitoSession: StaticMockitoSession
     private lateinit var handler: DesktopActivityOrientationChangeHandler
     private lateinit var shellInit: ShellInit
-    private lateinit var taskRepository: DesktopRepository
+    private lateinit var userRepositories: DesktopUserRepositories
     private lateinit var testScope: CoroutineScope
     // Mock running tasks are registered here so we can get the list from mock shell task organizer.
     private val runningTasks = mutableListOf<RunningTaskInfo>()
@@ -117,13 +119,14 @@
 
         testScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob())
         shellInit = spy(ShellInit(testExecutor))
-        taskRepository =
-            DesktopRepository(
+        userRepositories =
+            DesktopUserRepositories(
                 context,
                 shellInit,
                 persistentRepository,
                 repositoryInitializer,
-                testScope
+                testScope,
+                userManager
             )
         whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenAnswer { runningTasks }
         whenever(transitions.startTransition(anyInt(), any(), isNull())).thenAnswer { Binder() }
@@ -132,7 +135,7 @@
         )
 
         handler = DesktopActivityOrientationChangeHandler(context, shellInit, shellTaskOrganizer,
-            taskStackListener, resizeTransitionHandler, taskRepository)
+            taskStackListener, resizeTransitionHandler, userRepositories)
 
         shellInit.init()
     }
@@ -156,7 +159,7 @@
         clearInvocations(shellInit)
 
         handler = DesktopActivityOrientationChangeHandler(context, shellInit, shellTaskOrganizer,
-            taskStackListener, resizeTransitionHandler, taskRepository)
+            taskStackListener, resizeTransitionHandler, userRepositories)
 
         verify(shellInit, never()).addInitCallback(any(),
             any<DesktopActivityOrientationChangeHandler>())
@@ -180,7 +183,7 @@
         activityInfo.screenOrientation = SCREEN_ORIENTATION_PORTRAIT
         task.topActivityInfo = activityInfo
         whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
-        taskRepository.addTask(DEFAULT_DISPLAY, task.taskId, isVisible = true)
+        userRepositories.current.addTask(DEFAULT_DISPLAY, task.taskId, isVisible = true)
         runningTasks.add(task)
 
         taskStackListener.onActivityRequestedOrientationChanged(task.taskId,
@@ -203,7 +206,7 @@
     @Test
     fun handleActivityOrientationChange_notInDesktopMode_doNothing() {
         val task = setUpFreeformTask(isResizeable = false)
-        taskRepository.updateTask(task.displayId, task.taskId, isVisible = false)
+        userRepositories.current.updateTask(task.displayId, task.taskId, isVisible = false)
 
         taskStackListener.onActivityRequestedOrientationChanged(task.taskId,
             SCREEN_ORIENTATION_LANDSCAPE)
@@ -268,7 +271,7 @@
         task.topActivityInfo = activityInfo
         task.isResizeable = isResizeable
         whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
-        taskRepository.addTask(displayId, task.taskId, isVisible = true)
+        userRepositories.current.addTask(displayId, task.taskId, isVisible = true)
         runningTasks.add(task)
         return task
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt
index 4666276..db4c746 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt
@@ -43,7 +43,7 @@
 import com.android.wm.shell.common.DisplayController
 import com.android.wm.shell.common.DisplayLayout
 import com.android.wm.shell.desktopmode.DesktopImmersiveController.ExitReason.USER_INTERACTION
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
 import com.android.wm.shell.sysui.ShellInit
 import com.android.wm.shell.transition.Transitions
 import com.android.wm.shell.util.StubTransaction
@@ -76,18 +76,19 @@
     @JvmField @Rule val animatorTestRule = AnimatorTestRule(this)
 
     @Mock private lateinit var mockTransitions: Transitions
-    private lateinit var desktopRepository: DesktopRepository
+    private lateinit var userRepositories: DesktopUserRepositories
     @Mock private lateinit var mockDisplayController: DisplayController
     @Mock private lateinit var mockShellTaskOrganizer: ShellTaskOrganizer
     @Mock private lateinit var mockDisplayLayout: DisplayLayout
     private val transactionSupplier = { StubTransaction() }
 
     private lateinit var controller: DesktopImmersiveController
+    private lateinit var desktopRepository: DesktopRepository
 
     @Before
     fun setUp() {
-        desktopRepository = DesktopRepository(
-            context, ShellInit(TestShellExecutor()), mock(), mock(), mock()
+        userRepositories = DesktopUserRepositories(
+            context, ShellInit(TestShellExecutor()), mock(), mock(), mock(), mock()
         )
         whenever(mockDisplayController.getDisplayLayout(DEFAULT_DISPLAY))
             .thenReturn(mockDisplayLayout)
@@ -97,12 +98,13 @@
         controller = DesktopImmersiveController(
             shellInit = mock(),
             transitions = mockTransitions,
-            desktopRepository = desktopRepository,
+            desktopUserRepositories = userRepositories,
             displayController = mockDisplayController,
             shellTaskOrganizer = mockShellTaskOrganizer,
             shellCommandHandler = mock(),
             transactionSupplier = transactionSupplier,
         )
+        desktopRepository = userRepositories.current
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt
index 62717a3..2d55445 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt
@@ -60,6 +60,7 @@
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
+import org.mockito.Mockito
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.kotlin.any
@@ -84,7 +85,7 @@
     @Mock
     lateinit var transitions: Transitions
     @Mock
-    lateinit var desktopRepository: DesktopRepository
+    lateinit var userRepositories: DesktopUserRepositories
     @Mock
     lateinit var freeformTaskTransitionHandler: FreeformTaskTransitionHandler
     @Mock
@@ -103,16 +104,21 @@
     lateinit var shellInit: ShellInit
     @Mock
     lateinit var rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
+    @Mock
+    private lateinit var desktopRepository: DesktopRepository
 
     private lateinit var mixedHandler: DesktopMixedTransitionHandler
 
+
     @Before
     fun setUp() {
+        whenever(userRepositories.current).thenReturn(desktopRepository)
+        whenever(userRepositories.getProfile(Mockito.anyInt())).thenReturn(desktopRepository)
         mixedHandler =
             DesktopMixedTransitionHandler(
                 context,
                 transitions,
-                desktopRepository,
+                userRepositories,
                 freeformTaskTransitionHandler,
                 closeDesktopTaskTransitionHandler,
                 desktopImmersiveController,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
index 7adc339..dc7fb5f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
@@ -38,7 +38,7 @@
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer
 import com.android.wm.shell.ShellTaskOrganizer
 import com.android.wm.shell.ShellTestCase
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
 import com.android.wm.shell.transition.FocusTransitionObserver
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -53,10 +53,9 @@
 import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
 import com.android.dx.mockito.inline.extended.StaticMockitoSession
 import com.android.window.flags.Flags.FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
+import com.android.wm.shell.TestShellExecutor
 import com.android.wm.shell.common.DisplayController
 import com.android.wm.shell.common.DisplayLayout
-import com.android.wm.shell.common.ShellExecutor
-import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
 import com.android.wm.shell.sysui.ShellInit
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel
@@ -91,7 +90,7 @@
     private val rootTaskDisplayAreaOrganizer = mock<RootTaskDisplayAreaOrganizer>()
     private val shellTaskOrganizer = mock<ShellTaskOrganizer>()
     private val focusTransitionObserver = mock<FocusTransitionObserver>()
-    private val testExecutor = mock<ShellExecutor>()
+    private val testExecutor = TestShellExecutor()
     private val inputManager = mock<InputManager>()
     private val displayController = mock<DisplayController>()
     private val displayLayout = mock<DisplayLayout>()
@@ -134,6 +133,17 @@
             null
         }.whenever(inputManager).registerKeyGestureEventHandler(any())
         shellInit.init()
+
+        desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
+            context,
+            Optional.of(desktopModeWindowDecorViewModel),
+            Optional.of(desktopTasksController),
+            inputManager,
+            shellTaskOrganizer,
+            focusTransitionObserver,
+            testExecutor,
+            displayController
+        )
     }
 
     @After
@@ -142,6 +152,7 @@
 
         runningTasks.clear()
         testScope.cancel()
+        testExecutor.flushAll()
     }
 
     @Test
@@ -151,11 +162,6 @@
         FLAG_USE_KEY_GESTURE_EVENT_HANDLER
     )
     fun keyGestureMoveToNextDisplay_shouldMoveToNextDisplay() {
-        desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
-            context,
-            Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
-            inputManager, shellTaskOrganizer, focusTransitionObserver
-        )
         // Set up two display ids
         whenever(rootTaskDisplayAreaOrganizer.displayIds)
             .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY))
@@ -187,11 +193,6 @@
         FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
     )
     fun keyGestureSnapLeft_shouldSnapResizeTaskToLeft() {
-        desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
-            context,
-            Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
-            inputManager, shellTaskOrganizer, focusTransitionObserver
-        )
         val task = setUpFreeformTask()
         task.isFocused = true
         whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
@@ -205,9 +206,7 @@
         val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
 
         assertThat(result).isTrue()
-        verify(desktopModeWindowDecorViewModel).onSnapResize(
-            task.taskId, true, DesktopModeEventLogger.Companion.InputMethod.KEYBOARD
-        )
+        assertThat(testExecutor.callbacks.size).isEqualTo(1)
     }
 
     @Test
@@ -216,11 +215,6 @@
         FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
     )
     fun keyGestureSnapRight_shouldSnapResizeTaskToRight() {
-        desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
-            context,
-            Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
-            inputManager, shellTaskOrganizer, focusTransitionObserver
-        )
         val task = setUpFreeformTask()
         task.isFocused = true
         whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
@@ -234,9 +228,7 @@
         val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
 
         assertThat(result).isTrue()
-        verify(desktopModeWindowDecorViewModel).onSnapResize(
-            task.taskId, false, DesktopModeEventLogger.Companion.InputMethod.KEYBOARD
-        )
+        assertThat(testExecutor.callbacks.size).isEqualTo(1)
     }
 
     @Test
@@ -245,11 +237,6 @@
         FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
     )
     fun keyGestureToggleFreeformWindowSize_shouldToggleTaskSize() {
-        desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
-            context,
-            Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
-            inputManager, shellTaskOrganizer, focusTransitionObserver
-        )
         val task = setUpFreeformTask()
         task.isFocused = true
         whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
@@ -263,11 +250,7 @@
         val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
 
         assertThat(result).isTrue()
-        verify(desktopTasksController).toggleDesktopTaskSize(
-            task,
-            ResizeTrigger.MAXIMIZE_MENU,
-            null
-        )
+        assertThat(testExecutor.callbacks.size).isEqualTo(1)
     }
 
     @Test
@@ -276,11 +259,6 @@
         FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
     )
     fun keyGestureMinimizeFreeformWindow_shouldMinimizeTask() {
-        desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
-            context,
-            Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
-            inputManager, shellTaskOrganizer, focusTransitionObserver
-        )
         val task = setUpFreeformTask()
         task.isFocused = true
         whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
@@ -294,7 +272,7 @@
         val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
 
         assertThat(result).isTrue()
-        verify(desktopTasksController).minimizeTask(task)
+        assertThat(testExecutor.callbacks.size).isEqualTo(1)
     }
 
     private fun setUpFreeformTask(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLoggerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLoggerTest.kt
index 51b291c0..94698e2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLoggerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLoggerTest.kt
@@ -17,17 +17,22 @@
 package com.android.wm.shell.desktopmode
 
 
+import android.content.ComponentName
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.InstanceId
-import com.android.internal.logging.InstanceIdSequence
 import com.android.internal.logging.testing.UiEventLoggerFake
 import com.android.wm.shell.ShellTestCase
-import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.Companion.DesktopUiEventEnum.DESKTOP_WINDOW_EDGE_DRAG_RESIZE
+import com.android.wm.shell.TestRunningTaskInfoBuilder
+import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventEnum.DESKTOP_WINDOW_EDGE_DRAG_RESIZE
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
 
 /**
  * Test class for [DesktopModeUiEventLogger]
@@ -39,13 +44,13 @@
 class DesktopModeUiEventLoggerTest : ShellTestCase() {
     private lateinit var uiEventLoggerFake: UiEventLoggerFake
     private lateinit var logger: DesktopModeUiEventLogger
-    private val instanceIdSequence = InstanceIdSequence(/* instanceIdMax */ 1 shl 20)
 
+    private val mockPackageManager: PackageManager = mock<PackageManager>()
 
     @Before
     fun setUp() {
         uiEventLoggerFake = UiEventLoggerFake()
-        logger = DesktopModeUiEventLogger(uiEventLoggerFake, instanceIdSequence)
+        logger = DesktopModeUiEventLogger(uiEventLoggerFake, mockPackageManager)
     }
 
     @Test
@@ -102,10 +107,28 @@
         assertThat(uiEventLoggerFake[0].packageName).isEqualTo(PACKAGE_NAME)
     }
 
+    @Test
+    fun logWithTaskInfo_eventLogged() {
+        val event =
+            DESKTOP_WINDOW_EDGE_DRAG_RESIZE
+        val taskInfo = TestRunningTaskInfoBuilder()
+            .setUserId(USER_ID)
+            .setBaseActivity(ComponentName(PACKAGE_NAME, "test"))
+            .build()
+        whenever(mockPackageManager.getApplicationInfoAsUser(PACKAGE_NAME, /* flags= */ 0, USER_ID))
+            .thenReturn(ApplicationInfo().apply { uid = UID })
+        logger.log(taskInfo, event)
+        assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
+        assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(event.id)
+        assertThat(uiEventLoggerFake[0].instanceId).isNull()
+        assertThat(uiEventLoggerFake[0].uid).isEqualTo(UID)
+        assertThat(uiEventLoggerFake[0].packageName).isEqualTo(PACKAGE_NAME)
+    }
 
     companion object {
         private val INSTANCE_ID = InstanceId.fakeInstanceId(0)
         private const val UID = 10
+        private const val USER_ID = 2
         private const val PACKAGE_NAME = "com.foo"
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
index 7f790d5..9059d7d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
@@ -30,7 +30,6 @@
 import com.android.wm.shell.common.ShellExecutor
 import com.android.wm.shell.desktopmode.persistence.Desktop
 import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
-import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer
 import com.android.wm.shell.sysui.ShellInit
 import com.google.common.truth.Truth.assertThat
 import junit.framework.Assert.fail
@@ -70,7 +69,6 @@
 
     @Mock private lateinit var testExecutor: ShellExecutor
     @Mock private lateinit var persistentRepository: DesktopPersistentRepository
-    @Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer
 
     @Before
     fun setUp() {
@@ -80,11 +78,9 @@
 
         repo =
             DesktopRepository(
-                context,
-                shellInit,
                 persistentRepository,
-                repositoryInitializer,
-                datastoreScope
+                datastoreScope,
+                DEFAULT_USER_ID
             )
         whenever(runBlocking { persistentRepository.readDesktop(any(), any()) }).thenReturn(
             Desktop.getDefaultInstance()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt
index e977966..b4daa66 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt
@@ -22,13 +22,15 @@
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
 import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION
+import com.android.wm.shell.desktopmode.DesktopUserRepositories
 import com.android.wm.shell.ShellTestCase
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTask
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.never
 import org.mockito.kotlin.verify
@@ -47,131 +49,163 @@
 
   private lateinit var desktopTaskChangeListener: DesktopTaskChangeListener
 
+  private val desktopUserRepositories = mock<DesktopUserRepositories>()
   private val desktopRepository = mock<DesktopRepository>()
 
   @Before
   fun setUp() {
-    desktopTaskChangeListener = DesktopTaskChangeListener(desktopRepository)
+    desktopTaskChangeListener = DesktopTaskChangeListener(desktopUserRepositories)
+
+    whenever(desktopUserRepositories.current).thenReturn(desktopRepository)
+    whenever(desktopUserRepositories.getProfile(anyInt())).thenReturn(desktopRepository)
   }
 
   @Test
   fun onTaskOpening_fullscreenTask_notActiveDesktopTask_noop() {
     val task = createFullscreenTask().apply { isVisible = true }
-    whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(false)
+    whenever(desktopUserRepositories.current.isActiveTask(task.taskId))
+        .thenReturn(false)
 
     desktopTaskChangeListener.onTaskOpening(task)
 
-    verify(desktopRepository, never()).addTask(task.displayId, task.taskId, task.isVisible)
-    verify(desktopRepository, never()).removeFreeformTask(task.displayId, task.taskId)
+    verify(desktopUserRepositories.current, never())
+        .addTask(task.displayId, task.taskId, task.isVisible)
+    verify(desktopUserRepositories.current, never())
+        .removeFreeformTask(task.displayId, task.taskId)
   }
 
   @Test
   fun onTaskOpening_freeformTask_activeDesktopTask_removesTaskFromRepo() {
     val task = createFullscreenTask().apply { isVisible = true }
-    whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true)
+    whenever(desktopUserRepositories.current.isActiveTask(task.taskId))
+        .thenReturn(true)
 
     desktopTaskChangeListener.onTaskOpening(task)
 
-    verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId)
+    verify(desktopUserRepositories.current).removeFreeformTask(task.displayId, task.taskId)
   }
 
   @Test
   fun onTaskOpening_freeformTask_visibleDesktopTask_addsTaskToRepository() {
     val task = createFreeformTask().apply { isVisible = true }
-    whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(false)
+    whenever(desktopUserRepositories.current.isActiveTask(task.taskId))
+        .thenReturn(false)
 
     desktopTaskChangeListener.onTaskOpening(task)
 
-    verify(desktopRepository).addTask(task.displayId, task.taskId, task.isVisible)
+    verify(desktopUserRepositories.current)
+        .addTask(task.displayId, task.taskId, task.isVisible)
   }
 
   @Test
   fun onTaskOpening_freeformTask_nonVisibleDesktopTask_addsTaskToRepository() {
     val task = createFreeformTask().apply { isVisible = false }
-    whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true)
+    whenever(desktopUserRepositories.current.isActiveTask(task.taskId))
+        .thenReturn(true)
 
     desktopTaskChangeListener.onTaskOpening(task)
 
-    verify(desktopRepository).addTask(task.displayId, task.taskId, task.isVisible)
+    verify(desktopUserRepositories.current)
+        .addTask(task.displayId, task.taskId, task.isVisible)
   }
 
   @Test
   fun onTaskChanging_freeformTaskOutsideDesktop_removesTaskFromRepo() {
     val task = createFullscreenTask().apply { isVisible = true }
-    whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true)
+    whenever(desktopUserRepositories.current.isActiveTask(task.taskId))
+        .thenReturn(true)
 
     desktopTaskChangeListener.onTaskChanging(task)
 
-    verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId)
+    verify(desktopUserRepositories.current)
+        .removeFreeformTask(task.displayId, task.taskId)
   }
 
   @Test
   fun onTaskChanging_visibleTaskInDesktop_updatesTaskVisibility() {
     val task = createFreeformTask().apply { isVisible = true }
-    whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true)
+    whenever(desktopUserRepositories.current.isActiveTask(task.taskId))
+        .thenReturn(true)
 
     desktopTaskChangeListener.onTaskChanging(task)
 
-    verify(desktopRepository).updateTask(task.displayId, task.taskId, task.isVisible)
+    verify(desktopUserRepositories.current)
+        .updateTask(task.displayId, task.taskId, task.isVisible)
   }
 
   @Test
   fun onTaskChanging_nonVisibleTask_updatesTaskVisibility() {
     val task = createFreeformTask().apply { isVisible = false }
-    whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true)
+    whenever(desktopUserRepositories.current.isActiveTask(task.taskId))
+        .thenReturn(true)
 
     desktopTaskChangeListener.onTaskChanging(task)
 
-    verify(desktopRepository).updateTask(task.displayId, task.taskId, task.isVisible)
+    verify(desktopUserRepositories.current)
+        .updateTask(task.displayId, task.taskId, task.isVisible)
   }
 
   @Test
   fun onTaskMovingToFront_freeformTaskOutsideDesktop_removesTaskFromRepo() {
     val task = createFullscreenTask().apply { isVisible = true }
-    whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true)
+    whenever(desktopUserRepositories.current.isActiveTask(task.taskId))
+        .thenReturn(true)
 
     desktopTaskChangeListener.onTaskMovingToFront(task)
 
-    verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId)
+    verify(desktopUserRepositories.current)
+        .removeFreeformTask(task.displayId, task.taskId)
   }
 
   @Test
   @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION)
   fun onTaskClosing_backNavEnabled_nonClosingTask_minimizesTaskInRepo() {
     val task = createFreeformTask().apply { isVisible = true }
-    whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true)
-    whenever(desktopRepository.isClosingTask(task.taskId)).thenReturn(false)
+    whenever(desktopUserRepositories.current.isActiveTask(task.taskId))
+        .thenReturn(true)
+    whenever(desktopUserRepositories.current.isClosingTask(task.taskId))
+        .thenReturn(false)
 
     desktopTaskChangeListener.onTaskClosing(task)
 
-    verify(desktopRepository).updateTask(task.displayId, task.taskId, isVisible = false)
-    verify(desktopRepository).minimizeTask(task.displayId, task.taskId)
+    verify(desktopUserRepositories.current)
+        .updateTask(task.displayId, task.taskId, isVisible = false)
+    verify(desktopUserRepositories.current)
+        .minimizeTask(task.displayId, task.taskId)
   }
 
   @Test
   @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION)
   fun onTaskClosing_backNavDisabled_closingTask_removesTaskInRepo() {
     val task = createFreeformTask().apply { isVisible = true }
-    whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true)
-    whenever(desktopRepository.isClosingTask(task.taskId)).thenReturn(true)
+    whenever(desktopUserRepositories.current.isActiveTask(task.taskId))
+        .thenReturn(true)
+    whenever(desktopUserRepositories.current.isClosingTask(task.taskId))
+        .thenReturn(true)
 
     desktopTaskChangeListener.onTaskClosing(task)
 
-    verify(desktopRepository, never()).minimizeTask(task.displayId, task.taskId)
-    verify(desktopRepository).removeClosingTask(task.taskId)
-    verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId)
+    verify(desktopUserRepositories.current, never())
+        .minimizeTask(task.displayId, task.taskId)
+    verify(desktopUserRepositories.current)
+        .removeClosingTask(task.taskId)
+    verify(desktopUserRepositories.current)
+        .removeFreeformTask(task.displayId, task.taskId)
   }
 
   @Test
   @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION)
   fun onTaskClosing_backNavEnabled_closingTask_removesTaskFromRepo() {
     val task = createFreeformTask().apply { isVisible = true }
-    whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true)
-    whenever(desktopRepository.isClosingTask(task.taskId)).thenReturn(true)
+    whenever(desktopUserRepositories.current.isActiveTask(task.taskId))
+        .thenReturn(true)
+    whenever(desktopUserRepositories.current.isClosingTask(task.taskId))
+        .thenReturn(true)
 
     desktopTaskChangeListener.onTaskClosing(task)
 
-    verify(desktopRepository).removeClosingTask(task.taskId)
-    verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId)
+    verify(desktopUserRepositories.current).removeClosingTask(task.taskId)
+    verify(desktopUserRepositories.current)
+        .removeFreeformTask(task.displayId, task.taskId)
   }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index a8cfef7..c10434a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -44,6 +44,7 @@
 import android.os.Bundle
 import android.os.Handler
 import android.os.IBinder
+import android.os.UserManager
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.SetFlagsRule
@@ -93,16 +94,17 @@
 import com.android.wm.shell.common.MultiInstanceHelper
 import com.android.wm.shell.common.ShellExecutor
 import com.android.wm.shell.common.SyncTransactionQueue
+import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction
 import com.android.wm.shell.desktopmode.DesktopImmersiveController.ExitResult
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
 import com.android.wm.shell.desktopmode.DesktopTasksController.DesktopModeEntryExitTransitionListener
 import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition
 import com.android.wm.shell.desktopmode.DesktopTasksController.TaskbarDesktopTaskListener
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createHomeTask
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createSplitScreenTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createHomeTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createSplitScreenTask
 import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION
 import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler.FULLSCREEN_ANIMATION_DURATION
 import com.android.wm.shell.desktopmode.minimize.DesktopWindowLimitRemoteHandler
@@ -220,6 +222,7 @@
   @Mock private lateinit var freeformTaskTransitionStarter: FreeformTaskTransitionStarter
   @Mock private lateinit var mockHandler: Handler
   @Mock private lateinit var desktopModeEventLogger: DesktopModeEventLogger
+  @Mock private lateinit var desktopModeUiEventLogger: DesktopModeUiEventLogger
   @Mock lateinit var persistentRepository: DesktopPersistentRepository
   @Mock lateinit var motionEvent: MotionEvent
   @Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer
@@ -232,9 +235,11 @@
   @Mock private lateinit var resources: Resources
   @Mock
   lateinit var desktopModeEnterExitTransitionListener: DesktopModeEntryExitTransitionListener
+  @Mock private lateinit var userManager: UserManager
   private lateinit var controller: DesktopTasksController
   private lateinit var shellInit: ShellInit
   private lateinit var taskRepository: DesktopRepository
+  private lateinit var userRepositories: DesktopUserRepositories
   private lateinit var desktopTasksLimiter: DesktopTasksLimiter
   private lateinit var recentsTransitionStateListener: RecentsTransitionStateListener
   private lateinit var testScope: CoroutineScope
@@ -266,12 +271,18 @@
 
     testScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob())
     shellInit = spy(ShellInit(testExecutor))
-    taskRepository =
-      DesktopRepository(context, shellInit, persistentRepository, repositoryInitializer, testScope)
+    userRepositories =
+      DesktopUserRepositories(
+        context,
+        shellInit,
+        persistentRepository,
+        repositoryInitializer,
+        testScope,
+        userManager)
     desktopTasksLimiter =
         DesktopTasksLimiter(
             transitions,
-            taskRepository,
+            userRepositories,
             shellTaskOrganizer,
             MAX_TASK_LIMIT,
             mockInteractionJankMonitor,
@@ -314,6 +325,8 @@
     controller.taskbarDesktopTaskListener = taskbarDesktopTaskListener
 
     assumeTrue(ENABLE_SHELL_TRANSITIONS)
+
+    taskRepository = userRepositories.current
   }
 
   private fun createController(): DesktopTasksController {
@@ -337,7 +350,7 @@
         toggleResizeDesktopTaskTransitionHandler,
         dragToDesktopTransitionHandler,
         mMockDesktopImmersiveController,
-        taskRepository,
+        userRepositories,
         recentsTransitionHandler,
         multiInstanceHelper,
         shellExecutor,
@@ -346,6 +359,7 @@
         mockInteractionJankMonitor,
         mockHandler,
         desktopModeEventLogger,
+        desktopModeUiEventLogger,
         desktopTilingDecorViewModel,
       )
   }
@@ -375,12 +389,19 @@
     val task1 = setUpFreeformTask()
 
     val argumentCaptor = ArgumentCaptor.forClass(Boolean::class.java)
-    controller.toggleDesktopTaskSize(task1, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(
+      task1,
+      ToggleTaskSizeInteraction(
+        ToggleTaskSizeInteraction.Direction.MAXIMIZE,
+        ToggleTaskSizeInteraction.Source.HEADER_BUTTON_TO_MAXIMIZE,
+        InputMethod.TOUCH
+      )
+    )
 
     verify(taskbarDesktopTaskListener).onTaskbarCornerRoundingUpdate(argumentCaptor.capture())
     verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
       ResizeTrigger.MAXIMIZE_BUTTON,
-      InputMethod.UNKNOWN_INPUT_METHOD,
+      InputMethod.TOUCH,
       task1,
       STABLE_BOUNDS.width(),
       STABLE_BOUNDS.height(),
@@ -397,21 +418,29 @@
   }
 
   @Test
-  fun doesAnyTaskRequireTaskbarRounding_toggleResizeOfFullScreenTask_returnFalse() {
+  fun doesAnyTaskRequireTaskbarRounding_toggleResizeOfMaximizedTask_returnFalse() {
     val stableBounds = Rect().apply { displayLayout.getStableBounds(this) }
     val task1 = setUpFreeformTask(bounds = stableBounds, active = true)
 
     val argumentCaptor = ArgumentCaptor.forClass(Boolean::class.java)
-    controller.toggleDesktopTaskSize(task1, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(
+      task1,
+      ToggleTaskSizeInteraction(
+        ToggleTaskSizeInteraction.Direction.RESTORE,
+        ToggleTaskSizeInteraction.Source.HEADER_BUTTON_TO_RESTORE,
+        InputMethod.TOUCH
+      )
+    )
 
     verify(taskbarDesktopTaskListener).onTaskbarCornerRoundingUpdate(argumentCaptor.capture())
     verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
-      ResizeTrigger.MAXIMIZE_BUTTON,
-      InputMethod.UNKNOWN_INPUT_METHOD,
-      task1,
-      0,
-      0,
-      displayController
+      eq(ResizeTrigger.MAXIMIZE_BUTTON),
+      eq(InputMethod.TOUCH),
+      eq(task1),
+      anyOrNull(),
+      anyOrNull(),
+      eq(displayController),
+      anyOrNull()
     )
     assertThat(argumentCaptor.value).isFalse()
   }
@@ -3357,14 +3386,21 @@
     val bounds = Rect(0, 0, 100, 100)
     val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds)
 
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(
+      task,
+      ToggleTaskSizeInteraction(
+        ToggleTaskSizeInteraction.Direction.MAXIMIZE,
+        ToggleTaskSizeInteraction.Source.HEADER_BUTTON_TO_MAXIMIZE,
+        InputMethod.TOUCH
+      )
+    )
 
     // Assert bounds set to stable bounds
     val wct = getLatestToggleResizeDesktopTaskWct()
     assertThat(findBoundsChange(wct, task)).isEqualTo(STABLE_BOUNDS)
     verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
       ResizeTrigger.MAXIMIZE_BUTTON,
-      InputMethod.UNKNOWN_INPUT_METHOD,
+      InputMethod.TOUCH,
       task,
       STABLE_BOUNDS.width(),
       STABLE_BOUNDS.height(),
@@ -3582,14 +3618,21 @@
     // Bounds should be 1000 x 500, vertically centered in the 1000 x 1000 stable bounds
     val expectedBounds = Rect(STABLE_BOUNDS.left, 250, STABLE_BOUNDS.right, 750)
 
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(
+      task,
+      ToggleTaskSizeInteraction(
+        ToggleTaskSizeInteraction.Direction.MAXIMIZE,
+        ToggleTaskSizeInteraction.Source.HEADER_BUTTON_TO_MAXIMIZE,
+        InputMethod.TOUCH
+      )
+    )
 
     // Assert bounds set to stable bounds
     val wct = getLatestToggleResizeDesktopTaskWct()
     assertThat(findBoundsChange(wct, task)).isEqualTo(expectedBounds)
     verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
       ResizeTrigger.MAXIMIZE_BUTTON,
-      InputMethod.UNKNOWN_INPUT_METHOD,
+      InputMethod.TOUCH,
       task,
       expectedBounds.width(),
       expectedBounds.height(),
@@ -3602,7 +3645,15 @@
     val bounds = Rect(0, 0, 100, 100)
     val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds)
 
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(
+      task,
+      ToggleTaskSizeInteraction(
+        ToggleTaskSizeInteraction.Direction.MAXIMIZE,
+        ToggleTaskSizeInteraction.Source.HEADER_BUTTON_TO_MAXIMIZE,
+        InputMethod.TOUCH
+      )
+    )
+
     assertThat(taskRepository.removeBoundsBeforeMaximize(task.taskId)).isEqualTo(bounds)
     verify(desktopModeEventLogger, never()).logTaskResizingEnded(
       any(), any(), any(), any(),
@@ -3616,18 +3667,32 @@
     val task = setUpFreeformTask(DEFAULT_DISPLAY, boundsBeforeMaximize)
 
     // Maximize
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(
+      task,
+      ToggleTaskSizeInteraction(
+        ToggleTaskSizeInteraction.Direction.MAXIMIZE,
+        ToggleTaskSizeInteraction.Source.HEADER_BUTTON_TO_MAXIMIZE,
+        InputMethod.TOUCH
+      )
+    )
     task.configuration.windowConfiguration.bounds.set(STABLE_BOUNDS)
 
     // Restore
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(
+      task,
+      ToggleTaskSizeInteraction(
+        ToggleTaskSizeInteraction.Direction.RESTORE,
+        ToggleTaskSizeInteraction.Source.HEADER_BUTTON_TO_RESTORE,
+        InputMethod.TOUCH
+      )
+    )
 
     // Assert bounds set to last bounds before maximize
     val wct = getLatestToggleResizeDesktopTaskWct()
     assertThat(findBoundsChange(wct, task)).isEqualTo(boundsBeforeMaximize)
     verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
       ResizeTrigger.MAXIMIZE_BUTTON,
-      InputMethod.UNKNOWN_INPUT_METHOD,
+      InputMethod.TOUCH,
       task,
       boundsBeforeMaximize.width(),
       boundsBeforeMaximize.height(),
@@ -3643,19 +3708,33 @@
     }
 
     // Maximize
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(
+      task,
+      ToggleTaskSizeInteraction(
+        ToggleTaskSizeInteraction.Direction.MAXIMIZE,
+        ToggleTaskSizeInteraction.Source.HEADER_BUTTON_TO_MAXIMIZE,
+        InputMethod.TOUCH
+      )
+    )
     task.configuration.windowConfiguration.bounds.set(STABLE_BOUNDS.left,
       boundsBeforeMaximize.top, STABLE_BOUNDS.right, boundsBeforeMaximize.bottom)
 
     // Restore
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(
+      task,
+      ToggleTaskSizeInteraction(
+        ToggleTaskSizeInteraction.Direction.RESTORE,
+        ToggleTaskSizeInteraction.Source.HEADER_BUTTON_TO_RESTORE,
+        InputMethod.TOUCH
+      )
+    )
 
     // Assert bounds set to last bounds before maximize
     val wct = getLatestToggleResizeDesktopTaskWct()
     assertThat(findBoundsChange(wct, task)).isEqualTo(boundsBeforeMaximize)
     verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
       ResizeTrigger.MAXIMIZE_BUTTON,
-      InputMethod.UNKNOWN_INPUT_METHOD,
+      InputMethod.TOUCH,
       task,
       boundsBeforeMaximize.width(),
       boundsBeforeMaximize.height(),
@@ -3671,19 +3750,33 @@
     }
 
     // Maximize
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(
+      task,
+      ToggleTaskSizeInteraction(
+        ToggleTaskSizeInteraction.Direction.MAXIMIZE,
+        ToggleTaskSizeInteraction.Source.HEADER_BUTTON_TO_MAXIMIZE,
+        InputMethod.TOUCH
+      )
+    )
     task.configuration.windowConfiguration.bounds.set(boundsBeforeMaximize.left,
       STABLE_BOUNDS.top, boundsBeforeMaximize.right, STABLE_BOUNDS.bottom)
 
     // Restore
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(
+      task,
+      ToggleTaskSizeInteraction(
+        ToggleTaskSizeInteraction.Direction.RESTORE,
+        ToggleTaskSizeInteraction.Source.HEADER_BUTTON_TO_RESTORE,
+        InputMethod.TOUCH
+      )
+    )
 
     // Assert bounds set to last bounds before maximize
     val wct = getLatestToggleResizeDesktopTaskWct()
     assertThat(findBoundsChange(wct, task)).isEqualTo(boundsBeforeMaximize)
     verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
       ResizeTrigger.MAXIMIZE_BUTTON,
-      InputMethod.UNKNOWN_INPUT_METHOD,
+      InputMethod.TOUCH,
       task,
       boundsBeforeMaximize.width(),
       boundsBeforeMaximize.height(),
@@ -3697,17 +3790,31 @@
     val task = setUpFreeformTask(DEFAULT_DISPLAY, boundsBeforeMaximize)
 
     // Maximize
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(
+      task,
+      ToggleTaskSizeInteraction(
+        ToggleTaskSizeInteraction.Direction.MAXIMIZE,
+        ToggleTaskSizeInteraction.Source.HEADER_BUTTON_TO_MAXIMIZE,
+        InputMethod.TOUCH
+      )
+    )
     task.configuration.windowConfiguration.bounds.set(STABLE_BOUNDS)
 
     // Restore
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(
+      task,
+      ToggleTaskSizeInteraction(
+        ToggleTaskSizeInteraction.Direction.RESTORE,
+        ToggleTaskSizeInteraction.Source.HEADER_BUTTON_TO_RESTORE,
+        InputMethod.TOUCH
+      )
+    )
 
     // Assert last bounds before maximize removed after use
     assertThat(taskRepository.removeBoundsBeforeMaximize(task.taskId)).isNull()
     verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
       ResizeTrigger.MAXIMIZE_BUTTON,
-      InputMethod.UNKNOWN_INPUT_METHOD,
+      InputMethod.TOUCH,
       task,
       boundsBeforeMaximize.width(),
       boundsBeforeMaximize.height(),
@@ -3749,26 +3856,6 @@
   }
 
   @Test
-  fun toggleImmersive_enter_movesToImmersive() {
-    val task = setUpFreeformTask(DEFAULT_DISPLAY)
-    taskRepository.setTaskInFullImmersiveState(DEFAULT_DISPLAY, task.taskId, false /* immersive */)
-
-    controller.toggleDesktopTaskFullImmersiveState(task)
-
-    verify(mMockDesktopImmersiveController).moveTaskToImmersive(task)
-  }
-
-  @Test
-  fun toggleImmersive_exit_movesToNonImmersive() {
-    val task = setUpFreeformTask(DEFAULT_DISPLAY)
-    taskRepository.setTaskInFullImmersiveState(DEFAULT_DISPLAY, task.taskId, true /* immersive */)
-
-    controller.toggleDesktopTaskFullImmersiveState(task)
-
-    verify(mMockDesktopImmersiveController).moveTaskToNonImmersive(eq(task), any())
-  }
-
-  @Test
   @EnableFlags(FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
   fun onTaskInfoChanged_inImmersiveUnrequestsImmersive_exits() {
     val task = setUpFreeformTask(DEFAULT_DISPLAY)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
index 456b50d..0712d58 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
@@ -20,6 +20,7 @@
 import android.graphics.Rect
 import android.os.Binder
 import android.os.Handler
+import android.os.UserManager
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.SetFlagsRule
@@ -42,7 +43,7 @@
 import com.android.wm.shell.ShellTaskOrganizer
 import com.android.wm.shell.ShellTestCase
 import com.android.wm.shell.common.ShellExecutor
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
 import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
 import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
@@ -73,7 +74,6 @@
 import org.mockito.kotlin.verify
 import org.mockito.quality.Strictness
 
-
 /**
  * Test class for {@link DesktopTasksLimiter}
  *
@@ -95,9 +95,11 @@
     @Mock lateinit var testExecutor: ShellExecutor
     @Mock lateinit var persistentRepository: DesktopPersistentRepository
     @Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer
+    @Mock lateinit var userManager: UserManager
 
     private lateinit var mockitoSession: StaticMockitoSession
     private lateinit var desktopTasksLimiter: DesktopTasksLimiter
+    private lateinit var userRepositories: DesktopUserRepositories
     private lateinit var desktopTaskRepo: DesktopRepository
     private lateinit var shellInit: ShellInit
     private lateinit var testScope: CoroutineScope
@@ -111,16 +113,18 @@
         Dispatchers.setMain(StandardTestDispatcher())
         testScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob())
 
-        desktopTaskRepo =
-            DesktopRepository(
+        userRepositories =
+            DesktopUserRepositories(
                 context,
                 shellInit,
                 persistentRepository,
                 repositoryInitializer,
-                testScope
+                testScope,
+                userManager
             )
+        desktopTaskRepo = userRepositories.current
         desktopTasksLimiter =
-            DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, MAX_TASK_LIMIT,
+            DesktopTasksLimiter(transitions, userRepositories, shellTaskOrganizer, MAX_TASK_LIMIT,
                 interactionJankMonitor, mContext, handler)
     }
 
@@ -133,7 +137,7 @@
     @Test
     fun createDesktopTasksLimiter_withZeroLimit_shouldThrow() {
         assertFailsWith<IllegalArgumentException> {
-            DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, 0,
+            DesktopTasksLimiter(transitions, userRepositories, shellTaskOrganizer, 0,
                 interactionJankMonitor, mContext, handler)
         }
     }
@@ -141,7 +145,7 @@
     @Test
     fun createDesktopTasksLimiter_withNegativeLimit_shouldThrow() {
         assertFailsWith<IllegalArgumentException> {
-            DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, -5,
+            DesktopTasksLimiter(transitions, userRepositories, shellTaskOrganizer, -5,
                 interactionJankMonitor, mContext, handler)
         }
     }
@@ -411,7 +415,7 @@
     @Test
     fun getTaskToMinimize_tasksAboveLimit_otherLimit_returnsBackTask() {
         desktopTasksLimiter =
-            DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, MAX_TASK_LIMIT2,
+            DesktopTasksLimiter(transitions, userRepositories, shellTaskOrganizer, MAX_TASK_LIMIT2,
                 interactionJankMonitor, mContext, handler)
         val tasks = (1..MAX_TASK_LIMIT2 + 1).map { setUpFreeformTask() }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt
index 7f1c1db..238483d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt
@@ -50,6 +50,7 @@
 import org.junit.Rule
 import org.junit.Test
 import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.ArgumentMatchers.eq
 import org.mockito.ArgumentMatchers.isA
 import org.mockito.Mockito
@@ -75,6 +76,7 @@
     private val transitions = mock<Transitions>()
     private val context = mock<Context>()
     private val shellTaskOrganizer = mock<ShellTaskOrganizer>()
+    private val userRepositories = mock<DesktopUserRepositories>()
     private val taskRepository = mock<DesktopRepository>()
     private val mixedHandler = mock<DesktopMixedTransitionHandler>()
 
@@ -86,9 +88,12 @@
         whenever(DesktopModeStatus.canEnterDesktopMode(any())).thenReturn(true)
         shellInit = spy(ShellInit(testExecutor))
 
+        whenever(userRepositories.current).thenReturn(taskRepository)
+        whenever(userRepositories.getProfile(anyInt())).thenReturn(taskRepository)
+
         transitionObserver =
             DesktopTasksTransitionObserver(
-                context, taskRepository, transitions, shellTaskOrganizer, mixedHandler, shellInit
+                context, userRepositories, transitions, shellTaskOrganizer, mixedHandler, shellInit
             )
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt
index 2134f3b..866d1b3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt
@@ -27,78 +27,56 @@
 import com.android.wm.shell.MockToken
 import com.android.wm.shell.TestRunningTaskInfoBuilder
 
-class DesktopTestHelpers {
-    companion object {
-        /** Create a task that has windowing mode set to [WINDOWING_MODE_FREEFORM] */
-        @JvmStatic
-        @JvmOverloads
-        fun createFreeformTask(
-                displayId: Int = DEFAULT_DISPLAY,
-                bounds: Rect? = null
-        ): RunningTaskInfo {
-            return TestRunningTaskInfoBuilder()
-                    .setDisplayId(displayId)
-                    .setToken(MockToken().token())
-                    .setActivityType(ACTIVITY_TYPE_STANDARD)
-                    .setWindowingMode(WINDOWING_MODE_FREEFORM)
-                    .setLastActiveTime(100)
-                    .apply { bounds?.let { setBounds(it) }}
-                    .build()
-        }
+object DesktopTestHelpers {
+    /** Create a task that has windowing mode set to [WINDOWING_MODE_FREEFORM] */
+    fun createFreeformTask(
+        displayId: Int = DEFAULT_DISPLAY,
+        bounds: Rect? = null,
+    ): RunningTaskInfo =
+        TestRunningTaskInfoBuilder()
+            .setDisplayId(displayId)
+            .setToken(MockToken().token())
+            .setActivityType(ACTIVITY_TYPE_STANDARD)
+            .setWindowingMode(WINDOWING_MODE_FREEFORM)
+            .setLastActiveTime(100)
+            .apply { bounds?.let { setBounds(it) } }
+            .build()
 
-        /** Create a task builder that has windowing mode set to [WINDOWING_MODE_FULLSCREEN] */
-        @JvmStatic
-        @JvmOverloads
-        fun createFullscreenTaskBuilder(displayId: Int = DEFAULT_DISPLAY): TestRunningTaskInfoBuilder {
-            return TestRunningTaskInfoBuilder()
-                .setDisplayId(displayId)
-                .setToken(MockToken().token())
-                .setActivityType(ACTIVITY_TYPE_STANDARD)
-                .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
-                .setLastActiveTime(100)
-        }
+    fun createFullscreenTaskBuilder(displayId: Int = DEFAULT_DISPLAY): TestRunningTaskInfoBuilder =
+        TestRunningTaskInfoBuilder()
+            .setDisplayId(displayId)
+            .setToken(MockToken().token())
+            .setActivityType(ACTIVITY_TYPE_STANDARD)
+            .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+            .setLastActiveTime(100)
 
-        /** Create a task that has windowing mode set to [WINDOWING_MODE_FULLSCREEN] */
-        @JvmStatic
-        @JvmOverloads
-        fun createFullscreenTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
-            return createFullscreenTaskBuilder(displayId).build()
-        }
+    /** Create a task that has windowing mode set to [WINDOWING_MODE_FULLSCREEN] */
+    fun createFullscreenTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo =
+        createFullscreenTaskBuilder(displayId).build()
 
-        /** Create a task that has windowing mode set to [WINDOWING_MODE_MULTI_WINDOW] */
-        @JvmStatic
-        @JvmOverloads
-        fun createSplitScreenTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
-            return TestRunningTaskInfoBuilder()
-                .setDisplayId(displayId)
-                .setToken(MockToken().token())
-                .setActivityType(ACTIVITY_TYPE_STANDARD)
-                .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW)
-                .setLastActiveTime(100)
-                .build()
-        }
+    /** Create a task that has windowing mode set to [WINDOWING_MODE_MULTI_WINDOW] */
+    fun createSplitScreenTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo =
+        TestRunningTaskInfoBuilder()
+            .setDisplayId(displayId)
+            .setToken(MockToken().token())
+            .setActivityType(ACTIVITY_TYPE_STANDARD)
+            .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW)
+            .setLastActiveTime(100)
+            .build()
 
-        /** Create a new home task */
-        @JvmStatic
-        @JvmOverloads
-        fun createHomeTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
-            return TestRunningTaskInfoBuilder()
-                    .setDisplayId(displayId)
-                    .setToken(MockToken().token())
-                    .setActivityType(ACTIVITY_TYPE_HOME)
-                    .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
-                    .setLastActiveTime(100)
-                    .build()
-        }
+    fun createHomeTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo =
+        TestRunningTaskInfoBuilder()
+            .setDisplayId(displayId)
+            .setToken(MockToken().token())
+            .setActivityType(ACTIVITY_TYPE_HOME)
+            .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+            .setLastActiveTime(100)
+            .build()
 
-        /** Create a new System Modal task, i.e. a task with a single transparent activity. */
-        @JvmStatic
-        @JvmOverloads
-        fun createSystemModalTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
-            return createFullscreenTaskBuilder(displayId)
-                .setTopActivityTransparent(true)
-                .setNumActivities(1)
-                .build()
-        }
-    }
-}
\ No newline at end of file
+    /** Create a new System Modal task, i.e. a task with a single transparent activity. */
+    fun createSystemModalTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo =
+        createFullscreenTaskBuilder(displayId)
+            .setTopActivityTransparent(true)
+            .setNumActivities(1)
+            .build()
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt
index 79d9083..b9d7bbf 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt
@@ -25,10 +25,11 @@
 import androidx.test.filters.SmallTest
 import com.android.wm.shell.ShellTestCase
 import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTaskBuilder
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createSystemModalTask
 import com.android.wm.shell.desktopmode.DesktopRepository
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTaskBuilder
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createSystemModalTask
+import com.android.wm.shell.desktopmode.DesktopUserRepositories
 import com.android.wm.shell.sysui.ShellInit
 import com.android.wm.shell.transition.TransitionInfoBuilder
 import com.android.wm.shell.transition.Transitions
@@ -49,6 +50,7 @@
     private val animExecutor = mock<ShellExecutor>()
     private val shellInit = mock<ShellInit>()
     private val transitions = mock<Transitions>()
+    private val desktopUserRepositories = mock<DesktopUserRepositories>()
     private val desktopRepository = mock<DesktopRepository>()
     private val startT = mock<SurfaceControl.Transaction>()
     private val finishT = mock<SurfaceControl.Transaction>()
@@ -58,6 +60,7 @@
     @Before
     fun setUp() {
         // Simulate having one Desktop task so that we see Desktop Mode as active
+        whenever(desktopUserRepositories.current).thenReturn(desktopRepository)
         whenever(desktopRepository.getVisibleTaskCount(anyInt())).thenReturn(1)
         transitionHandler = createTransitionHandler()
     }
@@ -69,7 +72,7 @@
             animExecutor,
             shellInit,
             transitions,
-            desktopRepository,
+            desktopUserRepositories,
         )
 
     @Test
@@ -79,7 +82,7 @@
 
     @Test
     fun startAnimation_desktopNotActive_doesNotAnimate() {
-        whenever(desktopRepository.getVisibleTaskCount(anyInt())).thenReturn(1)
+        whenever(desktopUserRepositories.current.getVisibleTaskCount(anyInt())).thenReturn(1)
         val info =
             TransitionInfoBuilder(TRANSIT_OPEN)
                 .addChange(TRANSIT_OPEN, createSystemModalTask())
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt
index d94186c..9c00c0c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt
@@ -175,13 +175,13 @@
 
   @Test
   @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
-  fun init_educationViewedAlready_shouldNotCallShowEducationTooltip() =
+  fun init_appHandleHintViewedAlready_shouldNotCallShowEducationTooltip() =
       testScope.runTest {
-        // App handle is visible but education has been viewed before. Should not show education
-        // tooltip.
-        // Mark education viewed.
+        // App handle is visible but app handle hint has been viewed before,
+        // should not show education tooltip.
+        // Mark app handle hint viewed.
         testDataStoreFlow.value =
-            createWindowingEducationProto(educationViewedTimestampMillis = 123L)
+            createWindowingEducationProto(appHandleHintViewedTimestampMillis = 123L)
         setShouldShowAppHandleEducation(true)
 
         // Simulate app handle visible.
@@ -194,13 +194,14 @@
 
   @Test
   @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
-  fun overridePrerequisite_educationViewedAlready_shouldCallShowEducationTooltip() =
+  fun overridePrerequisite_appHandleHintViewedAlready_shouldCallShowEducationTooltip() =
       testScope.runTest {
-        // App handle is visible but education has been viewed before. But as we are overriding
-        // prerequisite conditions, we should show education tooltip.
-        // Mark education viewed.
+        // App handle is visible but app handle hint has been viewed before.
+        // But as we are overriding prerequisite conditions, we should show app
+        // handle tooltip.
+        // Mark app handle hint viewed.
         testDataStoreFlow.value =
-            createWindowingEducationProto(educationViewedTimestampMillis = 123L)
+            createWindowingEducationProto(appHandleHintViewedTimestampMillis = 123L)
         val systemPropertiesKey =
             "persist.desktop_windowing_app_handle_education_override_conditions"
         whenever(SystemProperties.getBoolean(eq(systemPropertiesKey), anyBoolean()))
@@ -217,7 +218,7 @@
 
   @Test
   @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
-  fun init_appHandleExpanded_shouldMarkFeatureViewed() =
+  fun init_appHandleExpanded_shouldMarkAppHandleHintUsed() =
       testScope.runTest {
         setShouldShowAppHandleEducation(false)
 
@@ -226,12 +227,12 @@
         // Wait for some time before verifying
         waitForBufferDelay()
 
-        verify(mockDataStoreRepository, times(1)).updateFeatureUsedTimestampMillis(eq(true))
+        verify(mockDataStoreRepository, times(1)).updateAppHandleHintUsedTimestampMillis(eq(true))
       }
 
   @Test
   @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
-  fun init_showFirstTooltip_shouldMarkEducationViewed() =
+  fun init_showFirstTooltip_shouldMarkAppHandleHintViewed() =
       testScope.runTest {
         // App handle is visible. Should show education tooltip.
         setShouldShowAppHandleEducation(true)
@@ -241,7 +242,7 @@
         // Wait for first tooltip to showup.
         waitForBufferDelay()
 
-        verify(mockDataStoreRepository, times(1)).updateEducationViewedTimestampMillis(eq(true))
+        verify(mockDataStoreRepository, times(1)).updateAppHandleHintViewedTimestampMillis(eq(true))
       }
 
   @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationDatastoreRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationDatastoreRepositoryTest.kt
index c286544..963890d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationDatastoreRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationDatastoreRepositoryTest.kt
@@ -81,8 +81,8 @@
       runTest(StandardTestDispatcher()) {
         val windowingEducationProto =
             createWindowingEducationProto(
-                educationViewedTimestampMillis = 123L,
-                featureUsedTimestampMillis = 124L,
+                appHandleHintViewedTimestampMillis = 123L,
+                appHandleHintUsedTimestampMillis = 124L,
                 appUsageStats = mapOf(GMAIL_PACKAGE_NAME to 2),
                 appUsageStatsLastUpdateTimestampMillis = 125L)
         testDatastore.updateData { windowingEducationProto }
@@ -110,20 +110,20 @@
       }
 
   @Test
-  fun updateEducationViewedTimestampMillis_updatesDatastoreProto() =
+  fun updateAppHandleHintViewedTimestampMillis_updatesDatastoreProto() =
       runTest(StandardTestDispatcher()) {
-        datastoreRepository.updateEducationViewedTimestampMillis(true)
+        datastoreRepository.updateAppHandleHintViewedTimestampMillis(true)
 
-        val result = testDatastore.data.first().hasEducationViewedTimestampMillis()
+        val result = testDatastore.data.first().hasAppHandleHintViewedTimestampMillis()
         assertThat(result).isEqualTo(true)
       }
 
   @Test
-  fun updateFeatureUsedTimestampMillis_updatesDatastoreProto() =
+  fun updateAppHandleHintUsedTimestampMillis_updatesDatastoreProto() =
       runTest(StandardTestDispatcher()) {
-        datastoreRepository.updateFeatureUsedTimestampMillis(true)
+        datastoreRepository.updateAppHandleHintUsedTimestampMillis(true)
 
-        val result = testDatastore.data.first().hasFeatureUsedTimestampMillis()
+        val result = testDatastore.data.first().hasAppHandleHintUsedTimestampMillis()
         assertThat(result).isEqualTo(true)
       }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilterTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilterTest.kt
index a3e74e8..e5edd69 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilterTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilterTest.kt
@@ -134,12 +134,12 @@
   }
 
   @Test
-  fun shouldShowAppHandleEducation_educationViewedBefore_returnsFalse() = runTest {
-    // Education has been viewed before, hence #shouldShowAppHandleEducation should return false
+  fun shouldShowAppHandleEducation_appHandleHintViewedBefore_returnsFalse() = runTest {
+    // App handle hint has been viewed before, hence #shouldShowAppHandleEducation should return false
     val windowingEducationProto =
         createWindowingEducationProto(
             appUsageStats = mapOf(GMAIL_PACKAGE_NAME to 4),
-            educationViewedTimestampMillis = 123L,
+            appHandleHintViewedTimestampMillis = 123L,
             appUsageStatsLastUpdateTimestampMillis = Long.MAX_VALUE)
     `when`(datastoreRepository.windowingEducationProto()).thenReturn(windowingEducationProto)
 
@@ -149,12 +149,12 @@
   }
 
   @Test
-  fun shouldShowAppHandleEducation_featureUsedBefore_returnsFalse() = runTest {
-    // Feature has been used before, hence #shouldShowAppHandleEducation should return false
+  fun shouldShowAppHandleEducation_appHandleHintUsedBefore_returnsFalse() = runTest {
+    // App handle hint has been used before, hence #shouldShowAppHandleEducation should return false
     val windowingEducationProto =
         createWindowingEducationProto(
             appUsageStats = mapOf(GMAIL_PACKAGE_NAME to 4),
-            featureUsedTimestampMillis = 123L,
+            appHandleHintUsedTimestampMillis = 123L,
             appUsageStatsLastUpdateTimestampMillis = Long.MAX_VALUE)
     `when`(datastoreRepository.windowingEducationProto()).thenReturn(windowingEducationProto)
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepositoryTest.kt
index 8495580..4f7e80c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepositoryTest.kt
@@ -112,7 +112,8 @@
             datastoreRepository.addOrUpdateDesktop(
                 visibleTasks = visibleTasks,
                 minimizedTasks = minimizedTasks,
-                freeformTasksInZOrder = freeformTasksInZOrder)
+                freeformTasksInZOrder = freeformTasksInZOrder,
+                userId = DEFAULT_USER_ID)
 
             val actualDesktop = datastoreRepository.readDesktop(DEFAULT_USER_ID, DEFAULT_DESKTOP_ID)
             assertThat(actualDesktop?.tasksByTaskIdMap).hasSize(2)
@@ -135,7 +136,8 @@
             datastoreRepository.addOrUpdateDesktop(
                 visibleTasks = visibleTasks,
                 minimizedTasks = minimizedTasks,
-                freeformTasksInZOrder = freeformTasksInZOrder)
+                freeformTasksInZOrder = freeformTasksInZOrder,
+                userId = DEFAULT_USER_ID)
 
             val actualDesktop = datastoreRepository.readDesktop(DEFAULT_USER_ID, DEFAULT_DESKTOP_ID)
             assertThat(actualDesktop?.tasksByTaskIdMap?.get(task.taskId)?.desktopTaskState)
@@ -158,7 +160,8 @@
             datastoreRepository.addOrUpdateDesktop(
                 visibleTasks = visibleTasks,
                 minimizedTasks = minimizedTasks,
-                freeformTasksInZOrder = freeformTasksInZOrder)
+                freeformTasksInZOrder = freeformTasksInZOrder,
+                userId = DEFAULT_USER_ID)
 
             val actualDesktop = datastoreRepository.readDesktop(DEFAULT_USER_ID, DEFAULT_DESKTOP_ID)
             assertThat(actualDesktop?.tasksByTaskIdMap).isEmpty()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt
index 9753429..1c88a29 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt
@@ -16,14 +16,17 @@
 
 package com.android.wm.shell.desktopmode.persistence
 
+import android.os.UserManager
 import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
 import android.testing.AndroidTestingRunner
 import android.view.Display.DEFAULT_DISPLAY
 import androidx.test.filters.SmallTest
+import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_HSUM
 import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE
 import com.android.wm.shell.ShellTestCase
 import com.android.wm.shell.common.ShellExecutor
-import com.android.wm.shell.desktopmode.DesktopRepository
+import com.android.wm.shell.desktopmode.DesktopUserRepositories
 import com.android.wm.shell.sysui.ShellInit
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineScope
@@ -36,26 +39,30 @@
 import kotlinx.coroutines.test.setMain
 import org.junit.After
 import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mockito.inOrder
 import org.mockito.Mockito.spy
-import org.mockito.kotlin.any
 import org.mockito.kotlin.mock
-import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
 
+
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
 @ExperimentalCoroutinesApi
 class DesktopRepositoryInitializerTest : ShellTestCase() {
 
+    @JvmField
+    @Rule
+    val setFlagsRule = SetFlagsRule()
+
     private lateinit var repositoryInitializer: DesktopRepositoryInitializer
     private lateinit var shellInit: ShellInit
     private lateinit var datastoreScope: CoroutineScope
 
-    private lateinit var desktopRepository: DesktopRepository
+    private lateinit var desktopUserRepositories: DesktopUserRepositories
     private val persistentRepository = mock<DesktopPersistentRepository>()
+    private val userManager = mock<UserManager>()
     private val testExecutor = mock<ShellExecutor>()
 
     @Before
@@ -65,55 +72,193 @@
         datastoreScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob())
         repositoryInitializer =
             DesktopRepositoryInitializerImpl(context, persistentRepository, datastoreScope)
-        desktopRepository =
-            DesktopRepository(
-                context, shellInit, persistentRepository, repositoryInitializer, datastoreScope)
+        desktopUserRepositories =
+            DesktopUserRepositories(
+                context, shellInit, persistentRepository, repositoryInitializer, datastoreScope,
+                userManager
+            )
     }
 
     @Test
-    @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE)
-    fun initWithPersistence_multipleTasks_addedCorrectly() =
+    @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE, FLAG_ENABLE_DESKTOP_WINDOWING_HSUM)
+    fun initWithPersistence_multipleUsers_addedCorrectly() =
         runTest(StandardTestDispatcher()) {
-            val freeformTasksInZOrder = listOf(1, 2, 3)
-            whenever(persistentRepository.readDesktop(any(), any()))
-                .thenReturn(
-                    Desktop.newBuilder()
-                        .setDesktopId(1)
-                        .addAllZOrderedTasks(freeformTasksInZOrder)
-                        .putTasksByTaskId(
-                            1,
-                            DesktopTask.newBuilder()
-                                .setTaskId(1)
-                                .setDesktopTaskState(DesktopTaskState.VISIBLE)
-                                .build())
-                        .putTasksByTaskId(
-                            2,
-                            DesktopTask.newBuilder()
-                                .setTaskId(2)
-                                .setDesktopTaskState(DesktopTaskState.VISIBLE)
-                                .build())
-                        .putTasksByTaskId(
-                            3,
-                            DesktopTask.newBuilder()
-                                .setTaskId(3)
-                                .setDesktopTaskState(DesktopTaskState.MINIMIZED)
-                                .build())
-                        .build())
+            whenever(persistentRepository.getUserDesktopRepositoryMap()).thenReturn(
+                mapOf(
+                    USER_ID_1 to desktopRepositoryState1,
+                    USER_ID_2 to desktopRepositoryState2
+                )
+            )
+            whenever(persistentRepository.getDesktopRepositoryState(USER_ID_1))
+                .thenReturn(desktopRepositoryState1)
+            whenever(persistentRepository.getDesktopRepositoryState(USER_ID_2))
+                .thenReturn(desktopRepositoryState2)
+            whenever(persistentRepository.readDesktop(USER_ID_1, DESKTOP_ID_1))
+                .thenReturn(desktop1)
+            whenever(persistentRepository.readDesktop(USER_ID_1, DESKTOP_ID_2))
+                .thenReturn(desktop2)
+            whenever(persistentRepository.readDesktop(USER_ID_2, DESKTOP_ID_3))
+                .thenReturn(desktop3)
 
-            repositoryInitializer.initialize(desktopRepository)
+            repositoryInitializer.initialize(desktopUserRepositories)
 
-            verify(persistentRepository).readDesktop(any(), any())
-            assertThat(desktopRepository.getActiveTasks(DEFAULT_DISPLAY))
-                .containsExactly(1, 2, 3)
+            // Desktop Repository currently returns all tasks across desktops for a specific user
+            // since the repository currently doesn't handle desktops. This test logic should be updated
+            // once the repository handles multiple desktops.
+            assertThat(
+                desktopUserRepositories.getProfile(USER_ID_1)
+                    .getActiveTasks(DEFAULT_DISPLAY)
+            )
+                .containsExactly(1, 3, 4, 5)
                 .inOrder()
-            assertThat(desktopRepository.getExpandedTasksOrdered(DEFAULT_DISPLAY))
-                .containsExactly(1, 2)
+            assertThat(
+                desktopUserRepositories.getProfile(USER_ID_1)
+                    .getExpandedTasksOrdered(DEFAULT_DISPLAY)
+            )
+                .containsExactly(5, 1)
                 .inOrder()
-            assertThat(desktopRepository.getMinimizedTasks(DEFAULT_DISPLAY)).containsExactly(3)
+            assertThat(
+                desktopUserRepositories.getProfile(USER_ID_1)
+                    .getMinimizedTasks(DEFAULT_DISPLAY)
+            )
+                .containsExactly(3, 4)
+                .inOrder()
+
+            assertThat(
+                desktopUserRepositories.getProfile(USER_ID_2)
+                    .getActiveTasks(DEFAULT_DISPLAY)
+            )
+                .containsExactly(7, 8)
+                .inOrder()
+            assertThat(
+                desktopUserRepositories.getProfile(USER_ID_2)
+                    .getExpandedTasksOrdered(DEFAULT_DISPLAY)
+            )
+                .contains(7)
+            assertThat(
+                desktopUserRepositories.getProfile(USER_ID_2)
+                    .getMinimizedTasks(DEFAULT_DISPLAY)
+            ).containsExactly(8)
+        }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE)
+    fun initWithPersistence_singleUser_addedCorrectly() =
+        runTest(StandardTestDispatcher()) {
+            whenever(persistentRepository.getUserDesktopRepositoryMap()).thenReturn(
+                mapOf(
+                    USER_ID_1 to desktopRepositoryState1,
+                )
+            )
+            whenever(persistentRepository.getDesktopRepositoryState(USER_ID_1))
+                .thenReturn(desktopRepositoryState1)
+            whenever(persistentRepository.readDesktop(USER_ID_1, DESKTOP_ID_1))
+                .thenReturn(desktop1)
+            whenever(persistentRepository.readDesktop(USER_ID_1, DESKTOP_ID_2))
+                .thenReturn(desktop2)
+
+            repositoryInitializer.initialize(desktopUserRepositories)
+
+            // Desktop Repository currently returns all tasks across desktops for a specific user
+            // since the repository currently doesn't handle desktops. This test logic should be updated
+            // once the repository handles multiple desktops.
+            assertThat(
+                desktopUserRepositories.getProfile(USER_ID_1)
+                    .getActiveTasks(DEFAULT_DISPLAY)
+            )
+                .containsExactly(1, 3, 4, 5)
+                .inOrder()
+            assertThat(
+                desktopUserRepositories.getProfile(USER_ID_1)
+                    .getExpandedTasksOrdered(DEFAULT_DISPLAY)
+            )
+                .containsExactly(5, 1)
+                .inOrder()
+            assertThat(
+                desktopUserRepositories.getProfile(USER_ID_1)
+                    .getMinimizedTasks(DEFAULT_DISPLAY)
+            )
+                .containsExactly(3, 4)
+                .inOrder()
         }
 
     @After
     fun tearDown() {
         datastoreScope.cancel()
     }
+
+    private companion object {
+        const val USER_ID_1 = 5
+        const val USER_ID_2 = 6
+        const val DESKTOP_ID_1 = 2
+        const val DESKTOP_ID_2 = 3
+        const val DESKTOP_ID_3 = 4
+
+        val freeformTasksInZOrder1 = listOf(1, 3)
+        val desktop1: Desktop = Desktop.newBuilder()
+            .setDesktopId(DESKTOP_ID_1)
+            .addAllZOrderedTasks(freeformTasksInZOrder1)
+            .putTasksByTaskId(
+                1,
+                DesktopTask.newBuilder()
+                    .setTaskId(1)
+                    .setDesktopTaskState(DesktopTaskState.VISIBLE)
+                    .build()
+            )
+            .putTasksByTaskId(
+                3,
+                DesktopTask.newBuilder()
+                    .setTaskId(3)
+                    .setDesktopTaskState(DesktopTaskState.MINIMIZED)
+                    .build()
+            )
+            .build()
+
+        val freeformTasksInZOrder2 = listOf(4, 5)
+        val desktop2: Desktop = Desktop.newBuilder()
+            .setDesktopId(DESKTOP_ID_2)
+            .addAllZOrderedTasks(freeformTasksInZOrder2)
+            .putTasksByTaskId(
+                4,
+                DesktopTask.newBuilder()
+                    .setTaskId(4)
+                    .setDesktopTaskState(DesktopTaskState.MINIMIZED)
+                    .build()
+            )
+            .putTasksByTaskId(
+                5,
+                DesktopTask.newBuilder()
+                    .setTaskId(5)
+                    .setDesktopTaskState(DesktopTaskState.VISIBLE)
+                    .build()
+            )
+            .build()
+
+        val freeformTasksInZOrder3 = listOf(7, 8)
+        val desktop3: Desktop = Desktop.newBuilder()
+            .setDesktopId(DESKTOP_ID_3)
+            .addAllZOrderedTasks(freeformTasksInZOrder3)
+            .putTasksByTaskId(
+                7,
+                DesktopTask.newBuilder()
+                    .setTaskId(7)
+                    .setDesktopTaskState(DesktopTaskState.VISIBLE)
+                    .build()
+            )
+            .putTasksByTaskId(
+                8,
+                DesktopTask.newBuilder()
+                    .setTaskId(8)
+                    .setDesktopTaskState(DesktopTaskState.MINIMIZED)
+                    .build()
+            )
+            .build()
+        val desktopRepositoryState1: DesktopRepositoryState = DesktopRepositoryState.newBuilder()
+            .putDesktop(DESKTOP_ID_1, desktop1)
+            .putDesktop(DESKTOP_ID_2, desktop2)
+            .build()
+        val desktopRepositoryState2: DesktopRepositoryState = DesktopRepositoryState.newBuilder()
+            .putDesktop(DESKTOP_ID_3, desktop3)
+            .build()
+    }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java
index b504a88..794ba48 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java
@@ -27,6 +27,7 @@
 import static com.android.window.flags.Flags.FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -46,6 +47,7 @@
 import com.android.wm.shell.TestRunningTaskInfoBuilder;
 import com.android.wm.shell.common.LaunchAdjacentController;
 import com.android.wm.shell.desktopmode.DesktopRepository;
+import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.sysui.ShellInit;
@@ -81,6 +83,8 @@
     @Mock
     private SurfaceControl mMockSurfaceControl;
     @Mock
+    private DesktopUserRepositories mDesktopUserRepositories;
+    @Mock
     private DesktopRepository mDesktopRepository;
     @Mock
     private DesktopTasksController mDesktopTasksController;
@@ -101,13 +105,14 @@
                         .mockStatic(DesktopModeStatus.class)
                         .startMocking();
         doReturn(true).when(() -> DesktopModeStatus.canEnterDesktopMode(any()));
-
+        when(mDesktopUserRepositories.getCurrent()).thenReturn(mDesktopRepository);
+        when(mDesktopUserRepositories.getProfile(anyInt())).thenReturn(mDesktopRepository);
         mFreeformTaskListener =
                 new FreeformTaskListener(
                         mContext,
                         mShellInit,
                         mTaskOrganizer,
-                        Optional.of(mDesktopRepository),
+                        Optional.of(mDesktopUserRepositories),
                         Optional.of(mDesktopTasksController),
                         mLaunchAdjacentController,
                         mWindowDecorViewModel,
@@ -123,7 +128,8 @@
 
         mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl);
 
-        verify(mDesktopRepository).addTask(task.displayId, task.taskId, task.isVisible = true);
+        verify(mDesktopUserRepositories.getCurrent())
+                .addTask(task.displayId, task.taskId, task.isVisible = true);
     }
 
     @Test
@@ -135,7 +141,8 @@
 
         mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl);
 
-        verify(mDesktopRepository).addTask(task.displayId, task.taskId, task.isVisible);
+        verify(mDesktopUserRepositories.getCurrent())
+                .addTask(task.displayId, task.taskId, task.isVisible);
     }
 
     @Test
@@ -147,7 +154,8 @@
 
         mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl);
 
-        verify(mDesktopRepository, never()).addTask(task.displayId, task.taskId, task.isVisible);
+        verify(mDesktopUserRepositories.getCurrent(), never())
+                .addTask(task.displayId, task.taskId, task.isVisible);
     }
 
     @Test
@@ -158,7 +166,8 @@
 
         mFreeformTaskListener.onFocusTaskChanged(task);
 
-        verify(mDesktopRepository).addTask(task.displayId, task.taskId, task.isVisible);
+        verify(mDesktopUserRepositories.getCurrent())
+                .addTask(task.displayId, task.taskId, task.isVisible);
     }
 
     @Test
@@ -171,7 +180,7 @@
 
         mFreeformTaskListener.onFocusTaskChanged(fullscreenTask);
 
-        verify(mDesktopRepository, never())
+        verify(mDesktopUserRepositories.getCurrent(), never())
                 .addTask(fullscreenTask.displayId, fullscreenTask.taskId, fullscreenTask.isVisible);
     }
 
@@ -214,7 +223,7 @@
         task.displayId = INVALID_DISPLAY;
         mFreeformTaskListener.onTaskVanished(task);
 
-        verify(mDesktopRepository).minimizeTask(task.displayId, task.taskId);
+        verify(mDesktopUserRepositories.getCurrent()).minimizeTask(task.displayId, task.taskId);
     }
 
     @Test
@@ -227,14 +236,17 @@
 
         mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl);
 
-        when(mDesktopRepository.isClosingTask(task.taskId)).thenReturn(true);
+        when(mDesktopUserRepositories.getCurrent()
+                .isClosingTask(task.taskId)).thenReturn(true);
         task.isVisible = false;
         task.displayId = INVALID_DISPLAY;
         mFreeformTaskListener.onTaskVanished(task);
 
-        verify(mDesktopRepository, never()).minimizeTask(task.displayId, task.taskId);
-        verify(mDesktopRepository).removeClosingTask(task.taskId);
-        verify(mDesktopRepository).removeFreeformTask(task.displayId, task.taskId);
+        verify(mDesktopUserRepositories.getCurrent(), never())
+                .minimizeTask(task.displayId, task.taskId);
+        verify(mDesktopUserRepositories.getCurrent()).removeClosingTask(task.taskId);
+        verify(mDesktopUserRepositories.getCurrent())
+                .removeFreeformTask(task.displayId, task.taskId);
     }
 
     @Test
@@ -246,9 +258,12 @@
 
         mFreeformTaskListener.onTaskVanished(task);
 
-        verify(mDesktopRepository, never()).minimizeTask(task.displayId, task.taskId);
-        verify(mDesktopRepository, never()).removeClosingTask(task.taskId);
-        verify(mDesktopRepository, never()).removeFreeformTask(task.displayId, task.taskId);
+        verify(mDesktopUserRepositories.getCurrent(), never())
+                .minimizeTask(task.displayId, task.taskId);
+        verify(mDesktopUserRepositories.getCurrent(), never())
+                .removeClosingTask(task.taskId);
+        verify(mDesktopUserRepositories.getCurrent(), never())
+                .removeFreeformTask(task.displayId, task.taskId);
     }
 
     @Test
@@ -274,7 +289,8 @@
         mFreeformTaskListener.onTaskInfoChanged(task);
 
         verify(mTaskChangeListener, never()).onTaskChanging(any());
-        verify(mDesktopRepository).updateTask(task.displayId, task.taskId, task.isVisible);
+        verify(mDesktopUserRepositories.getCurrent())
+                .updateTask(task.displayId, task.taskId, task.isVisible);
     }
 
     @Test
@@ -289,7 +305,7 @@
         mFreeformTaskListener.onTaskInfoChanged(task);
 
         verify(mTaskChangeListener).onNonTransitionTaskChanging(any());
-        verify(mDesktopRepository, never())
+        verify(mDesktopUserRepositories.getCurrent(), never())
                 .updateTask(task.displayId, task.taskId, task.isVisible);
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 289fd2d..2eb2c3b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -65,7 +65,7 @@
 import com.android.wm.shell.common.pip.PipSnapAlgorithm;
 import com.android.wm.shell.common.pip.PipUiEventLogger;
 import com.android.wm.shell.common.pip.SizeSpecSource;
-import com.android.wm.shell.desktopmode.DesktopRepository;
+import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.pip.phone.PhonePipMenuController;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 
@@ -103,7 +103,7 @@
     @Mock private PipSurfaceTransactionHelper mMockPipSurfaceTransactionHelper;
     @Mock private PipUiEventLogger mMockPipUiEventLogger;
     @Mock private Optional<SplitScreenController> mMockOptionalSplitScreen;
-    @Mock private Optional<DesktopRepository> mMockOptionalDesktopRepository;
+    @Mock private Optional<DesktopUserRepositories> mMockOptionalDesktopUserRepositories;
     @Mock private RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
     @Mock private ShellTaskOrganizer mMockShellTaskOrganizer;
     @Mock private PipParamsChangedForwarder mMockPipParamsChangedForwarder;
@@ -136,7 +136,7 @@
                 mMockPipSurfaceTransactionHelper, mMockPipTransitionController,
                 mMockPipParamsChangedForwarder, mMockOptionalSplitScreen,
                 Optional.empty() /* pipPerfHintControllerOptional */,
-                mMockOptionalDesktopRepository, mRootTaskDisplayAreaOrganizer,
+                mMockOptionalDesktopUserRepositories, mRootTaskDisplayAreaOrganizer,
                 mMockDisplayController, mMockPipUiEventLogger, mMockShellTaskOrganizer,
                 mMainExecutor);
         mMainExecutor.flushAll();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
index cab6252..3fe8c10 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
@@ -42,8 +42,10 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
 import com.android.wm.shell.pip2.animation.PipAlphaAnimator;
@@ -56,6 +58,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Optional;
+
 /**
  * Unit test against {@link PipScheduler}
  */
@@ -79,6 +83,8 @@
     @Mock private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mMockFactory;
     @Mock private SurfaceControl.Transaction mMockTransaction;
     @Mock private PipAlphaAnimator mMockAlphaAnimator;
+    @Mock private Optional<DesktopUserRepositories> mMockOptionalDesktopUserRepositories;
+    @Mock private RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
 
     @Captor private ArgumentCaptor<Runnable> mRunnableArgumentCaptor;
     @Captor private ArgumentCaptor<WindowContainerTransaction> mWctArgumentCaptor;
@@ -96,7 +102,8 @@
                 .thenReturn(mMockTransaction);
 
         mPipScheduler = new PipScheduler(mMockContext, mMockPipBoundsState, mMockMainExecutor,
-                mMockPipTransitionState);
+                mMockPipTransitionState, mMockOptionalDesktopUserRepositories,
+                mRootTaskDisplayAreaOrganizer);
         mPipScheduler.setPipTransitionController(mMockPipTransitionController);
         mPipScheduler.setSurfaceControlTransactionFactory(mMockFactory);
         mPipScheduler.setPipAlphaAnimatorSupplier((context, leash, tx, direction) ->
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index 12c3978..95f371f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -22,9 +22,12 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.launcher3.Flags.FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL;
 import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -51,10 +54,12 @@
 import android.app.KeyguardManager;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Bundle;
+import android.os.UserManager;
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
@@ -72,6 +77,8 @@
 import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.desktopmode.DesktopRepository;
+import com.android.wm.shell.desktopmode.DesktopUserRepositories;
+import com.android.wm.shell.desktopmode.DesktopWallpaperActivity;
 import com.android.wm.shell.shared.GroupedTaskInfo;
 import com.android.wm.shell.shared.ShellSharedConstants;
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
@@ -110,8 +117,6 @@
     @Mock
     private ShellCommandHandler mShellCommandHandler;
     @Mock
-    private DesktopRepository mDesktopRepository;
-    @Mock
     private ActivityTaskManager mActivityTaskManager;
     @Mock
     private DisplayInsetsController mDisplayInsetsController;
@@ -119,6 +124,10 @@
     private IRecentTasksListener mRecentTasksListener;
     @Mock
     private TaskStackTransitionObserver mTaskStackTransitionObserver;
+    @Mock
+    private DesktopUserRepositories mDesktopUserRepositories;
+    @Mock
+    private DesktopRepository mDesktopRepository;
 
     @Rule
     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -139,6 +148,8 @@
                 .when(() -> DesktopModeStatus.canEnterDesktopMode(any()));
 
         mMainExecutor = new TestShellExecutor();
+        when(mDesktopUserRepositories.getCurrent()).thenReturn(mDesktopRepository);
+        when(mDesktopUserRepositories.getProfile(anyInt())).thenReturn(mDesktopRepository);
         when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class));
         when(mContext.getSystemService(KeyguardManager.class))
                 .thenReturn(mock(KeyguardManager.class));
@@ -147,7 +158,7 @@
                 mDisplayInsetsController, mMainExecutor));
         mRecentTasksControllerReal = new RecentTasksController(mContext, mShellInit,
                 mShellController, mShellCommandHandler, mTaskStackListener, mActivityTaskManager,
-                Optional.of(mDesktopRepository), mTaskStackTransitionObserver,
+                Optional.of(mDesktopUserRepositories), mTaskStackTransitionObserver,
                 mMainExecutor);
         mRecentTasksController = spy(mRecentTasksControllerReal);
         mShellTaskOrganizer = new ShellTaskOrganizer(mShellInit, mShellCommandHandler,
@@ -179,6 +190,12 @@
     }
 
     @Test
+    public void instantiateController_initializesRepository() {
+        verify(mDesktopUserRepositories, times(1)).getCurrent();
+        verify(mDesktopRepository, times(1)).addActiveTaskListener(any());
+    }
+
+    @Test
     public void testInvalidateExternalInterface_unregistersListener() {
         // Note: We have to use the real instance of the controller here since that is the instance
         // that is passed to ShellController internally, and the instance that the listener will be
@@ -237,6 +254,19 @@
                 t3.taskId, -1);
     }
 
+    @EnableFlags(FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL)
+    @Test
+    public void testGetRecentTasks_removesDesktopWallpaperActivity() {
+        RecentTaskInfo t1 = makeTaskInfo(1);
+        RecentTaskInfo desktopWallpaperTaskInfo = makeDesktopWallpaperTaskInfo(2);
+        RecentTaskInfo t3 = makeTaskInfo(3);
+        setRawList(t1, desktopWallpaperTaskInfo, t3);
+
+        ArrayList<GroupedTaskInfo> recentTasks =
+                mRecentTasksController.getRecentTasks(MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0);
+        assertGroupedTasksListEquals(recentTasks, t1.taskId, -1, t3.taskId, -1);
+    }
+
     @Test
     public void testGetRecentTasks_withPairs() {
         RecentTaskInfo t1 = makeTaskInfo(1);
@@ -307,8 +337,8 @@
         RecentTaskInfo t4 = makeTaskInfo(4);
         setRawList(t1, t2, t3, t4);
 
-        when(mDesktopRepository.isActiveTask(1)).thenReturn(true);
-        when(mDesktopRepository.isActiveTask(3)).thenReturn(true);
+        when(mDesktopUserRepositories.getCurrent().isActiveTask(1)).thenReturn(true);
+        when(mDesktopUserRepositories.getCurrent().isActiveTask(3)).thenReturn(true);
 
         ArrayList<GroupedTaskInfo> recentTasks =
                 mRecentTasksController.getRecentTasks(MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0);
@@ -346,8 +376,8 @@
                 new SplitBounds(new Rect(), new Rect(), 1, 2, SNAP_TO_2_50_50);
         mRecentTasksController.addSplitPair(t1.taskId, t2.taskId, pair1Bounds);
 
-        when(mDesktopRepository.isActiveTask(3)).thenReturn(true);
-        when(mDesktopRepository.isActiveTask(5)).thenReturn(true);
+        when(mDesktopUserRepositories.getCurrent().isActiveTask(3)).thenReturn(true);
+        when(mDesktopUserRepositories.getCurrent().isActiveTask(5)).thenReturn(true);
 
         ArrayList<GroupedTaskInfo> recentTasks =
                 mRecentTasksController.getRecentTasks(MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0);
@@ -386,8 +416,8 @@
         RecentTaskInfo t4 = makeTaskInfo(4);
         setRawList(t1, t2, t3, t4);
 
-        when(mDesktopRepository.isActiveTask(1)).thenReturn(true);
-        when(mDesktopRepository.isActiveTask(3)).thenReturn(true);
+        when(mDesktopUserRepositories.getCurrent().isActiveTask(1)).thenReturn(true);
+        when(mDesktopUserRepositories.getCurrent().isActiveTask(3)).thenReturn(true);
 
         ArrayList<GroupedTaskInfo> recentTasks =
                 mRecentTasksController.getRecentTasks(MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0);
@@ -415,7 +445,9 @@
         setRawList(t1, t2, t3, t4, t5);
 
         when(mDesktopRepository.isActiveTask(1)).thenReturn(true);
+        when(mDesktopRepository.isActiveTask(2)).thenReturn(false);
         when(mDesktopRepository.isActiveTask(3)).thenReturn(true);
+        when(mDesktopRepository.isActiveTask(4)).thenReturn(false);
         when(mDesktopRepository.isActiveTask(5)).thenReturn(true);
         when(mDesktopRepository.isMinimizedTask(3)).thenReturn(true);
 
@@ -454,8 +486,8 @@
         t2.lastNonFullscreenBounds = new Rect(150, 250, 350, 450);
         setRawList(t1, t2);
 
-        when(mDesktopRepository.isActiveTask(1)).thenReturn(true);
-        when(mDesktopRepository.isActiveTask(2)).thenReturn(true);
+        when(mDesktopUserRepositories.getCurrent().isActiveTask(1)).thenReturn(true);
+        when(mDesktopUserRepositories.getCurrent().isActiveTask(2)).thenReturn(true);
 
         ArrayList<GroupedTaskInfo> recentTasks =
                 mRecentTasksController.getRecentTasks(MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0);
@@ -691,11 +723,25 @@
     private RecentTaskInfo makeTaskInfo(int taskId) {
         RecentTaskInfo info = new RecentTaskInfo();
         info.taskId = taskId;
+
+        Intent intent = new Intent();
+        intent.setComponent(new ComponentName("com." + taskId, "Activity" + taskId));
+        info.baseIntent = intent;
+
         info.lastNonFullscreenBounds = new Rect();
         return info;
     }
 
     /**
+     * Helper to create a desktop wallpaper activity with a given task id.
+     */
+    private RecentTaskInfo makeDesktopWallpaperTaskInfo(int taskId) {
+        RecentTaskInfo info = makeTaskInfo(taskId);
+        info.baseIntent.setComponent(DesktopWallpaperActivity.getWallpaperActivityComponent());
+        return info;
+    }
+
+    /**
      * Helper to create a running task with a given task id.
      */
     private ActivityManager.RunningTaskInfo makeRunningTaskInfo(int taskId) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java
index f0f5fe1..894d238 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java
@@ -65,6 +65,7 @@
 import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.desktopmode.DesktopRepository;
+import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
@@ -100,7 +101,7 @@
     @Mock
     private ShellCommandHandler mShellCommandHandler;
     @Mock
-    private DesktopRepository mDesktopRepository;
+    private DesktopUserRepositories mDesktopUserRepositories;
     @Mock
     private ActivityTaskManager mActivityTaskManager;
     @Mock
@@ -112,6 +113,8 @@
     @Mock
     private Transitions mTransitions;
 
+    @Mock private DesktopRepository mDesktopRepository;
+
     @Rule
     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
@@ -131,6 +134,7 @@
         ExtendedMockito.doReturn(true)
                 .when(() -> DesktopModeStatus.canEnterDesktopMode(any()));
 
+        when(mDesktopUserRepositories.getCurrent()).thenReturn(mDesktopRepository);
         mMainExecutor = new TestShellExecutor();
         when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class));
         when(mContext.getSystemService(KeyguardManager.class))
@@ -140,7 +144,7 @@
                 mDisplayInsetsController, mMainExecutor));
         mRecentTasksControllerReal = new RecentTasksController(mContext, mShellInit,
                 mShellController, mShellCommandHandler, mTaskStackListener, mActivityTaskManager,
-                Optional.of(mDesktopRepository), mTaskStackTransitionObserver,
+                Optional.of(mDesktopUserRepositories), mTaskStackTransitionObserver,
                 mMainExecutor);
         mRecentTasksController = spy(mRecentTasksControllerReal);
         mShellTaskOrganizer = new ShellTaskOrganizer(mShellInit, mShellCommandHandler,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/TransitionObserverTestUtils.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/TransitionObserverTestUtils.kt
index 3e26ee0..a328b5b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/TransitionObserverTestUtils.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/TransitionObserverTestUtils.kt
@@ -36,7 +36,6 @@
 import android.window.WindowContainerToken
 import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn
 import com.android.wm.shell.transition.Transitions.TransitionObserver
-import org.mockito.Mockito
 import org.mockito.kotlin.mock
 
 @DslMarker
@@ -78,6 +77,30 @@
         validateObj.validate()
     }
 
+    fun validateOnMerged(
+        validate:
+        TransitionObserverOnTransitionMergedValidation.() -> Unit
+    ) {
+        val validateObj = TransitionObserverOnTransitionMergedValidation()
+        transitionObserver.onTransitionMerged(
+            validateObj.playing,
+            validateObj.merged
+        )
+        validateObj.validate()
+    }
+
+    fun validateOnFinished(
+        validate:
+        TransitionObserverOnTransitionFinishedValidation.() -> Unit
+    ) {
+        val validateObj = TransitionObserverOnTransitionFinishedValidation()
+        transitionObserver.onTransitionFinished(
+            transitionReadyInput.transition,
+            validateObj.aborted
+        )
+        validateObj.validate()
+    }
+
     fun invokeObservable() {
         transitionObserver.onTransitionReady(
             transitionReadyInput.transition,
@@ -93,10 +116,10 @@
  */
 class TransitionObserverInputBuilder : TransitionObserverTestStep {
 
-    private val transition = Mockito.mock(IBinder::class.java)
+    private val transition = mock<IBinder>()
     private var transitionInfo: TransitionInfo? = null
-    private val startTransaction = Mockito.mock(Transaction::class.java)
-    private val finishTransaction = Mockito.mock(Transaction::class.java)
+    private val startTransaction = mock<Transaction>()
+    private val finishTransaction = mock<Transaction>()
 
     fun buildTransitionInfo(
         @TransitionType type: Int = TRANSIT_NONE,
@@ -143,7 +166,7 @@
             taskId = id
             displayId = DEFAULT_DISPLAY
             configuration.windowConfiguration.windowingMode = windowingMode
-            token = WindowContainerToken(Mockito.mock(IWindowContainerToken::class.java))
+            token = WindowContainerToken(mock<IWindowContainerToken>())
             baseIntent = Intent().apply {
                 component = ComponentName("package", "component.name")
             }
@@ -163,6 +186,28 @@
 class TransitionObserverResultValidation : TransitionObserverTestStep
 
 /**
+ * Phase responsible for the execution of validation methods after the
+ * [TransitionObservable#onTransitionMerged] has been executed.
+ */
+class TransitionObserverOnTransitionMergedValidation : TransitionObserverTestStep {
+    val merged = mock<IBinder>()
+    val playing = mock<IBinder>()
+
+    init {
+        spyOn(merged)
+        spyOn(playing)
+    }
+}
+
+/**
+ * Phase responsible for the execution of validation methods after the
+ * [TransitionObservable#onTransitionFinished] has been executed.
+ */
+class TransitionObserverOnTransitionFinishedValidation : TransitionObserverTestStep {
+    var aborted: Boolean = false
+}
+
+/**
  * Allows to run a test about a specific [TransitionObserver] passing the specific
  * implementation and input value as parameters for the [TransitionObserver#onTransitionReady]
  * method.
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/WindowingEducationTestUtils.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/WindowingEducationTestUtils.kt
index 99e8295..b9d91e7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/WindowingEducationTestUtils.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/WindowingEducationTestUtils.kt
@@ -78,18 +78,18 @@
  * Any fields without corresponding parameters will retain their default values.
  */
 fun createWindowingEducationProto(
-    educationViewedTimestampMillis: Long? = null,
-    featureUsedTimestampMillis: Long? = null,
+    appHandleHintViewedTimestampMillis: Long? = null,
+    appHandleHintUsedTimestampMillis: Long? = null,
     appUsageStats: Map<String, Int>? = null,
     appUsageStatsLastUpdateTimestampMillis: Long? = null
 ): WindowingEducationProto =
     WindowingEducationProto.newBuilder()
         .apply {
-          if (educationViewedTimestampMillis != null) {
-            setEducationViewedTimestampMillis(educationViewedTimestampMillis)
+          if (appHandleHintViewedTimestampMillis != null) {
+            setAppHandleHintViewedTimestampMillis(appHandleHintViewedTimestampMillis)
           }
-          if (featureUsedTimestampMillis != null) {
-            setFeatureUsedTimestampMillis(featureUsedTimestampMillis)
+          if (appHandleHintUsedTimestampMillis != null) {
+            setAppHandleHintUsedTimestampMillis(appHandleHintUsedTimestampMillis)
           }
           setAppHandleEducation(
               createAppHandleEducationProto(appUsageStats, appUsageStatsLastUpdateTimestampMillis))
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorationTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorationTests.kt
index 59141ca..b856a28 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorationTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorationTests.kt
@@ -48,6 +48,7 @@
 
         CaptionWindowDecoration.updateRelayoutParams(
             relayoutParams,
+            mContext,
             taskInfo,
             true,
             false,
@@ -71,6 +72,7 @@
 
         CaptionWindowDecoration.updateRelayoutParams(
             relayoutParams,
+            mContext,
             taskInfo,
             true,
             false,
@@ -90,6 +92,7 @@
         val relayoutParams = WindowDecoration.RelayoutParams()
         CaptionWindowDecoration.updateRelayoutParams(
             relayoutParams,
+            mContext,
             taskInfo,
             true,
             false,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt
index 1215c52..4403558 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt
@@ -29,12 +29,13 @@
 import com.android.wm.shell.ShellTestCase
 import com.android.wm.shell.TestRunningTaskInfoBuilder
 import com.android.wm.shell.TestShellExecutor
-import com.android.wm.shell.desktopmode.DesktopRepository
+import com.android.wm.shell.desktopmode.DesktopUserRepositories
 import com.android.wm.shell.sysui.ShellInit
 import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
+import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -55,17 +56,18 @@
     @Rule
     val setFlagsRule: SetFlagsRule = SetFlagsRule()
 
-    private lateinit var desktopRepository: DesktopRepository
+    private lateinit var userRepositories: DesktopUserRepositories
     private lateinit var menu: DesktopHeaderManageWindowsMenu
 
     @Before
     fun setUp() {
-        desktopRepository = DesktopRepository(
+        userRepositories = DesktopUserRepositories(
             context = context,
             shellInit = ShellInit(TestShellExecutor()),
             persistentRepository = mock(),
             repositoryInitializer = mock(),
-            mainCoroutineScope = mock()
+            mainCoroutineScope = mock(),
+            userManager = mock(),
         )
     }
 
@@ -75,15 +77,15 @@
     }
 
     @Test
+    @Ignore("Test is failing internally")
     @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
     fun testShow_forImmersiveTask_usesSystemViewContainer() {
         val task = createFreeformTask()
-        desktopRepository.setTaskInFullImmersiveState(
+        userRepositories.getProfile(DEFAULT_USER_ID).setTaskInFullImmersiveState(
             displayId = task.displayId,
             taskId = task.taskId,
             immersive = true
         )
-
         menu = createMenu(task)
 
         assertThat(menu.menuViewContainer).isInstanceOf(AdditionalSystemViewContainer::class.java)
@@ -96,7 +98,7 @@
         displayController = mock(),
         rootTdaOrganizer = mock(),
         context = context,
-        desktopRepository = desktopRepository,
+        desktopUserRepositories = userRepositories,
         surfaceControlBuilderSupplier = { SurfaceControl.Builder() },
         surfaceControlTransactionSupplier = { SurfaceControl.Transaction() },
         snapshotList = emptyList(),
@@ -109,4 +111,8 @@
         .setActivityType(ACTIVITY_TYPE_STANDARD)
         .setWindowingMode(WINDOWING_MODE_FREEFORM)
         .build()
+
+    private companion object {
+        const val DEFAULT_USER_ID = 10
+    }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index 7bb8e891..a4e3af4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -59,6 +59,8 @@
 import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
 import com.android.window.flags.Flags
 import com.android.wm.shell.R
+import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction
+import com.android.wm.shell.desktopmode.DesktopImmersiveController
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
 import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition
@@ -398,8 +400,11 @@
 
         verify(mockDesktopTasksController).toggleDesktopTaskSize(
             decor.mTaskInfo,
-            ResizeTrigger.MAXIMIZE_MENU,
-            null
+            ToggleTaskSizeInteraction(
+                ToggleTaskSizeInteraction.Direction.MAXIMIZE,
+                ToggleTaskSizeInteraction.Source.MAXIMIZE_MENU_TO_MAXIMIZE,
+                InputMethod.UNKNOWN_INPUT_METHOD
+            )
         )
     }
 
@@ -1000,7 +1005,7 @@
 
     @Test
     @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
-    fun testMaximizeButtonClick_requestingImmersive_togglesDesktopImmersiveState() {
+    fun testImmersiveButtonClick_entersImmersiveMode() {
         val onClickListenerCaptor = forClass(View.OnClickListener::class.java)
                 as ArgumentCaptor<View.OnClickListener>
         val decor = createOpenTaskDecoration(
@@ -1010,11 +1015,35 @@
         )
         val view = mock(View::class.java)
         whenever(view.id).thenReturn(R.id.maximize_window)
+        whenever(mockDesktopRepository.isTaskInFullImmersiveState(decor.mTaskInfo.taskId))
+            .thenReturn(false)
 
         onClickListenerCaptor.value.onClick(view)
 
-        verify(mockDesktopTasksController)
-            .toggleDesktopTaskFullImmersiveState(decor.mTaskInfo)
+        verify(mockDesktopImmersiveController).moveTaskToImmersive(decor.mTaskInfo)
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+    fun testImmersiveRestoreButtonClick_exitsImmersiveMode() {
+        val onClickListenerCaptor = forClass(View.OnClickListener::class.java)
+                as ArgumentCaptor<View.OnClickListener>
+        val decor = createOpenTaskDecoration(
+            windowingMode = WINDOWING_MODE_FREEFORM,
+            onCaptionButtonClickListener = onClickListenerCaptor,
+            requestingImmersive = true,
+        )
+        val view = mock(View::class.java)
+        whenever(view.id).thenReturn(R.id.maximize_window)
+        whenever(mockDesktopRepository.isTaskInFullImmersiveState(decor.mTaskInfo.taskId))
+            .thenReturn(true)
+
+        onClickListenerCaptor.value.onClick(view)
+
+        verify(mockDesktopImmersiveController).moveTaskToNonImmersive(
+            decor.mTaskInfo,
+            DesktopImmersiveController.ExitReason.USER_INTERACTION
+        )
     }
 
     @Test
@@ -1033,23 +1062,31 @@
         onClickListenerCaptor.value.onClick(view)
 
         verify(mockDesktopTasksController)
-            .toggleDesktopTaskSize(decor.mTaskInfo, ResizeTrigger.MAXIMIZE_BUTTON, null)
+            .toggleDesktopTaskSize(
+                decor.mTaskInfo,
+                ToggleTaskSizeInteraction(
+                    ToggleTaskSizeInteraction.Direction.MAXIMIZE,
+                    ToggleTaskSizeInteraction.Source.HEADER_BUTTON_TO_MAXIMIZE,
+                    InputMethod.UNKNOWN_INPUT_METHOD
+                )
+            )
     }
 
     @Test
     @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
-    fun testImmersiveClick_togglesImmersiveState() {
+    fun testImmersiveMenuOptionClick_entersImmersiveMode() {
         val onImmersiveClickCaptor = argumentCaptor<() -> Unit>()
         val decor = createOpenTaskDecoration(
             windowingMode = WINDOWING_MODE_FREEFORM,
             onImmersiveOrRestoreListenerCaptor = onImmersiveClickCaptor,
             requestingImmersive = true,
         )
+        whenever(mockDesktopRepository.isTaskInFullImmersiveState(decor.mTaskInfo.taskId))
+            .thenReturn(false)
 
         onImmersiveClickCaptor.firstValue()
 
-        verify(mockDesktopTasksController)
-            .toggleDesktopTaskFullImmersiveState(decor.mTaskInfo)
+        verify(mockDesktopImmersiveController).moveTaskToImmersive(decor.mTaskInfo)
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
index 91eaada..afd4607 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
@@ -54,10 +54,13 @@
 import com.android.wm.shell.common.MultiInstanceHelper
 import com.android.wm.shell.common.SyncTransactionQueue
 import com.android.wm.shell.desktopmode.DesktopActivityOrientationChangeHandler
+import com.android.wm.shell.desktopmode.DesktopImmersiveController
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger
+import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger
 import com.android.wm.shell.desktopmode.DesktopRepository
 import com.android.wm.shell.desktopmode.DesktopTasksController
 import com.android.wm.shell.desktopmode.DesktopTasksLimiter
+import com.android.wm.shell.desktopmode.DesktopUserRepositories
 import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository
 import com.android.wm.shell.desktopmode.education.AppHandleEducationController
 import com.android.wm.shell.desktopmode.education.AppToWebEducationController
@@ -106,11 +109,12 @@
     protected val mockTaskOrganizer = mock<ShellTaskOrganizer>()
     protected val mockDisplayController = mock<DisplayController>()
     protected val mockSplitScreenController = mock<SplitScreenController>()
-    protected val mockDesktopRepository = mock<DesktopRepository>()
+    protected val mockDesktopUserRepositories = mock<DesktopUserRepositories>()
     protected val mockDisplayLayout = mock<DisplayLayout>()
     protected val displayInsetsController = mock<DisplayInsetsController>()
     protected val mockSyncQueue = mock<SyncTransactionQueue>()
     protected val mockDesktopTasksController = mock<DesktopTasksController>()
+    protected val mockDesktopImmersiveController = mock<DesktopImmersiveController>()
     protected val mockInputMonitor = mock<InputMonitor>()
     protected val mockTransitions = mock<Transitions>()
     internal val mockInputMonitorFactory =
@@ -139,6 +143,7 @@
     protected val mockAppToWebEducationController = mock<AppToWebEducationController>()
     protected val mockFocusTransitionObserver = mock<FocusTransitionObserver>()
     protected val mockCaptionHandleRepository = mock<WindowDecorCaptionHandleRepository>()
+    protected val mockDesktopRepository: DesktopRepository = mock<DesktopRepository>()
     protected val motionEvent = mock<MotionEvent>()
     val displayController = mock<DisplayController>()
     val displayLayout = mock<DisplayLayout>()
@@ -165,6 +170,9 @@
         windowDecorByTaskIdSpy.clear()
         spyContext.addMockSystemService(InputManager::class.java, mockInputManager)
         desktopModeEventLogger = mock<DesktopModeEventLogger>()
+        whenever(mockDesktopUserRepositories.current).thenReturn(mockDesktopRepository)
+        whenever(mockDesktopUserRepositories.getProfile(anyInt()))
+            .thenReturn(mockDesktopRepository)
         desktopModeWindowDecorViewModel = DesktopModeWindowDecorViewModel(
             spyContext,
             testShellExecutor,
@@ -175,13 +183,14 @@
             mockShellCommandHandler,
             mockWindowManager,
             mockTaskOrganizer,
-            mockDesktopRepository,
+            mockDesktopUserRepositories,
             mockDisplayController,
             mockShellController,
             displayInsetsController,
             mockSyncQueue,
             mockTransitions,
             Optional.of(mockDesktopTasksController),
+            mockDesktopImmersiveController,
             mockGenericLinksParser,
             mockAssistContentRequester,
             mockMultiInstanceHelper,
@@ -199,7 +208,8 @@
             Optional.of(mockActivityOrientationChangeHandler),
             mockTaskPositionerFactory,
             mockFocusTransitionObserver,
-            desktopModeEventLogger
+            desktopModeEventLogger,
+            mock<DesktopModeUiEventLogger>()
         )
         desktopModeWindowDecorViewModel.setSplitScreenController(mockSplitScreenController)
         whenever(mockDisplayController.getDisplayLayout(any())).thenReturn(mockDisplayLayout)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index f653622..61f3755 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -61,7 +61,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.PointF;
 import android.graphics.Rect;
@@ -110,6 +109,7 @@
 import com.android.wm.shell.desktopmode.CaptionState;
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger;
 import com.android.wm.shell.desktopmode.DesktopRepository;
+import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository;
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -166,7 +166,7 @@
     @Mock
     private ShellTaskOrganizer mMockShellTaskOrganizer;
     @Mock
-    private DesktopRepository mMockDesktopRepository;
+    private DesktopUserRepositories mMockDesktopUserRepositories;
     @Mock
     private Choreographer mMockChoreographer;
     @Mock
@@ -215,6 +215,8 @@
     private WindowDecorCaptionHandleRepository mMockCaptionHandleRepository;
     @Mock
     private DesktopModeEventLogger mDesktopModeEventLogger;
+    @Mock
+    private DesktopRepository mDesktopRepository;
     @Captor
     private ArgumentCaptor<Function1<Boolean, Unit>> mOnMaxMenuHoverChangeListener;
     @Captor
@@ -265,12 +267,14 @@
         doReturn(defaultDisplay).when(mMockDisplayController).getDisplay(Display.DEFAULT_DISPLAY);
         doReturn(mInsetsState).when(mMockDisplayController).getInsetsState(anyInt());
         when(mMockHandleMenuFactory.create(any(), any(), anyInt(), any(), any(), any(),
-                anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), any(),
-                anyInt(), anyInt(), anyInt(), anyInt()))
+                anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(),
+                any(), anyInt(), anyInt(), anyInt(), anyInt()))
                 .thenReturn(mMockHandleMenu);
         when(mMockMultiInstanceHelper.supportsMultiInstanceSplit(any())).thenReturn(false);
         when(mMockAppHeaderViewHolderFactory.create(any(), any(), any(), any(), any(), any(), any(),
                 any())).thenReturn(mMockAppHeaderViewHolder);
+        when(mMockDesktopUserRepositories.getCurrent()).thenReturn(mDesktopRepository);
+        when(mMockDesktopUserRepositories.getProfile(anyInt())).thenReturn(mDesktopRepository);
     }
 
     @After
@@ -295,8 +299,9 @@
     }
 
     @Test
-    public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreEnabled() {
+    public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreSetForFreeform() {
         final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
         RelayoutParams relayoutParams = new RelayoutParams();
 
         DesktopModeWindowDecoration.updateRelayoutParams(
@@ -309,7 +314,46 @@
                 /* hasGlobalFocus= */ true,
                 mExclusionRegion);
 
-        assertThat(relayoutParams.mShadowRadiusId).isNotEqualTo(Resources.ID_NULL);
+        assertThat(relayoutParams.mShadowRadius)
+                .isNotEqualTo(WindowDecoration.INVALID_SHADOW_RADIUS);
+    }
+
+    @Test
+    public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreNotSetForFullscreen() {
+        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        RelayoutParams relayoutParams = new RelayoutParams();
+
+        DesktopModeWindowDecoration.updateRelayoutParams(
+                relayoutParams, mContext, taskInfo, /* applyStartTransactionOnDraw= */ true,
+                /* shouldSetTaskPositionAndCrop */ false,
+                /* isStatusBarVisible */ true,
+                /* isKeyguardVisibleAndOccluded */ false,
+                /* inFullImmersiveMode */ false,
+                new InsetsState(),
+                /* hasGlobalFocus= */ true,
+                mExclusionRegion);
+
+        assertThat(relayoutParams.mShadowRadius).isEqualTo(WindowDecoration.INVALID_SHADOW_RADIUS);
+    }
+
+    @Test
+    public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreNotSetForSplit() {
+        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        RelayoutParams relayoutParams = new RelayoutParams();
+
+        DesktopModeWindowDecoration.updateRelayoutParams(
+                relayoutParams, mContext, taskInfo, /* applyStartTransactionOnDraw= */ true,
+                /* shouldSetTaskPositionAndCrop */ false,
+                /* isStatusBarVisible */ true,
+                /* isKeyguardVisibleAndOccluded */ false,
+                /* inFullImmersiveMode */ false,
+                new InsetsState(),
+                /* hasGlobalFocus= */ true,
+                mExclusionRegion);
+
+        assertThat(relayoutParams.mShadowRadius).isEqualTo(WindowDecoration.INVALID_SHADOW_RADIUS);
     }
 
     @Test
@@ -359,6 +403,29 @@
     }
 
     @Test
+    public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersNotSetForSplit() {
+        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        fillRoundedCornersResources(/* fillValue= */ 30);
+        RelayoutParams relayoutParams = new RelayoutParams();
+
+        DesktopModeWindowDecoration.updateRelayoutParams(
+                relayoutParams,
+                mTestableContext,
+                taskInfo,
+                /* applyStartTransactionOnDraw= */ true,
+                /* shouldSetTaskPositionAndCrop */ false,
+                /* isStatusBarVisible */ true,
+                /* isKeyguardVisibleAndOccluded */ false,
+                /* inFullImmersiveMode */ false,
+                new InsetsState(),
+                /* hasGlobalFocus= */ true,
+                mExclusionRegion);
+
+        assertThat(relayoutParams.mCornerRadius).isEqualTo(INVALID_CORNER_RADIUS);
+    }
+
+    @Test
     @EnableFlags(Flags.FLAG_ENABLE_APP_HEADER_WITH_TASK_DENSITY)
     public void updateRelayoutParams_appHeader_usesTaskDensity() {
         final int systemDensity = mTestableContext.getOrCreateTestableResources().getResources()
@@ -1407,8 +1474,8 @@
         final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
         final DesktopModeWindowDecoration decoration = createWindowDecoration(taskInfo,
                 true /* relayout */);
-        when(mMockDesktopRepository.isTaskInFullImmersiveState(taskInfo.taskId))
-                .thenReturn(true);
+        when(mMockDesktopUserRepositories.getCurrent()
+                .isTaskInFullImmersiveState(taskInfo.taskId)).thenReturn(true);
 
         createHandleMenu(decoration);
 
@@ -1429,7 +1496,7 @@
 
     @Test
     @DisableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION,
-            Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB_EDUCATION})
+            Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB_EDUCATION_INTEGRATION})
     public void notifyCaptionStateChanged_flagDisabled_doNoNotify() {
         when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
         final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
@@ -1577,7 +1644,8 @@
     private void verifyHandleMenuCreated(@Nullable Uri uri) {
         verify(mMockHandleMenuFactory).create(any(), any(), anyInt(), any(), any(),
                 any(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(),
-                argThat(intent -> (uri == null && intent == null) || intent.getData().equals(uri)),
+                anyBoolean(), argThat(intent ->
+                        (uri == null && intent == null) || intent.getData().equals(uri)),
                 anyInt(), anyInt(), anyInt(), anyInt());
     }
 
@@ -1642,8 +1710,8 @@
             boolean relayout) {
         final DesktopModeWindowDecoration windowDecor = new DesktopModeWindowDecoration(mContext,
                 mContext, mMockDisplayController, mMockSplitScreenController,
-                mMockDesktopRepository, mMockShellTaskOrganizer, taskInfo, mMockSurfaceControl,
-                mMockHandler, mBgExecutor, mMockChoreographer, mMockSyncQueue,
+                mMockDesktopUserRepositories, mMockShellTaskOrganizer, taskInfo,
+                mMockSurfaceControl, mMockHandler, mBgExecutor, mMockChoreographer, mMockSyncQueue,
                 mMockAppHeaderViewHolderFactory, mMockRootTaskDisplayAreaOrganizer,
                 mMockGenericLinksParser, mMockAssistContentRequester, SurfaceControl.Builder::new,
                 mMockTransactionSupplier, WindowContainerTransaction::new, SurfaceControl::new,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java
index e7d328e..479f156 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java
@@ -63,6 +63,7 @@
     private static final int EDGE_RESIZE_HANDLE_INSET = 4;
     private static final int FINE_CORNER_SIZE = EDGE_RESIZE_THICKNESS * 2 + 10;
     private static final int LARGE_CORNER_SIZE = FINE_CORNER_SIZE + 10;
+    private static final int SMALL_OFFSET = 10;
     private static final DragResizeWindowGeometry GEOMETRY = new DragResizeWindowGeometry(
             TASK_CORNER_RADIUS, TASK_SIZE, EDGE_RESIZE_THICKNESS, EDGE_RESIZE_HANDLE_INSET,
             FINE_CORNER_SIZE, LARGE_CORNER_SIZE, DragResizeWindowGeometry.DisabledEdge.NONE);
@@ -147,15 +148,19 @@
         assertThat(region.contains(point.x + EDGE_RESIZE_THICKNESS, point.y)).isTrue();
         assertThat(region.contains(point.x - EDGE_RESIZE_THICKNESS, point.y)).isTrue();
         // Vertically along the edge is not contained.
-        assertThat(region.contains(point.x, point.y - EDGE_RESIZE_THICKNESS)).isFalse();
-        assertThat(region.contains(point.x, point.y + EDGE_RESIZE_THICKNESS + 10)).isFalse();
+        assertThat(
+                region.contains(point.x, point.y - EDGE_RESIZE_THICKNESS - SMALL_OFFSET)).isFalse();
+        assertThat(
+                region.contains(point.x, point.y + EDGE_RESIZE_THICKNESS + SMALL_OFFSET)).isFalse();
     }
 
     private static void verifyVerticalEdge(@NonNull Region region, @NonNull Point point) {
         assertThat(region.contains(point.x, point.y)).isTrue();
         // Horizontally along the edge is not contained.
-        assertThat(region.contains(point.x + EDGE_RESIZE_THICKNESS, point.y)).isFalse();
-        assertThat(region.contains(point.x - EDGE_RESIZE_THICKNESS, point.y)).isFalse();
+        assertThat(
+                region.contains(point.x + EDGE_RESIZE_THICKNESS + SMALL_OFFSET, point.y)).isFalse();
+        assertThat(
+                region.contains(point.x - EDGE_RESIZE_THICKNESS - SMALL_OFFSET, point.y)).isFalse();
         // Vertically along the edge is contained.
         assertThat(region.contains(point.x, point.y - EDGE_RESIZE_THICKNESS)).isTrue();
         assertThat(region.contains(point.x, point.y + EDGE_RESIZE_THICKNESS)).isTrue();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt
index 7ec2cbf..6babf81 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt
@@ -266,8 +266,8 @@
             WindowManagerWrapper(mockWindowManager),
             layoutId, appIcon, appName, splitScreenController, shouldShowWindowingPill = true,
             shouldShowNewWindowButton = true, shouldShowManageWindowsButton = false,
-            shouldShowChangeAspectRatioButton = false, isBrowserApp = false,
-            null /* openInAppOrBrowserIntent */, captionWidth = HANDLE_WIDTH,
+            shouldShowChangeAspectRatioButton = false, shouldShowDesktopModeButton = true,
+            isBrowserApp = false, null /* openInAppOrBrowserIntent */, captionWidth = HANDLE_WIDTH,
             captionHeight = 50,
             captionX = captionX,
             captionY = 0,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index 534803d..04b2be0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -114,6 +114,7 @@
     private static final Rect TASK_BOUNDS = new Rect(100, 300, 400, 400);
     private static final Point TASK_POSITION_IN_PARENT = new Point(40, 60);
     private static final int CORNER_RADIUS = 20;
+    private static final int SHADOW_RADIUS = 10;
     private static final int STATUS_BAR_INSET_SOURCE_ID = 0;
 
     @Rule
@@ -162,7 +163,7 @@
         mRelayoutParams.mLayoutResId = 0;
         mRelayoutParams.mCaptionHeightId = R.dimen.test_freeform_decor_caption_height;
         mCaptionMenuWidthId = R.dimen.test_freeform_decor_caption_menu_width;
-        mRelayoutParams.mShadowRadiusId = R.dimen.test_window_decor_shadow_radius;
+        mRelayoutParams.mShadowRadius = SHADOW_RADIUS;
         mRelayoutParams.mCornerRadius = CORNER_RADIUS;
 
         when(mMockDisplayController.getDisplay(Display.DEFAULT_DISPLAY))
@@ -280,7 +281,7 @@
 
         verify(mMockSurfaceControlStartT).setCornerRadius(mMockTaskSurface, CORNER_RADIUS);
         verify(mMockSurfaceControlFinishT).setCornerRadius(mMockTaskSurface, CORNER_RADIUS);
-        verify(mMockSurfaceControlStartT).setShadowRadius(mMockTaskSurface, 10);
+        verify(mMockSurfaceControlStartT).setShadowRadius(mMockTaskSurface, SHADOW_RADIUS);
 
         assertEquals(300, mRelayoutResult.mWidth);
         assertEquals(100, mRelayoutResult.mHeight);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/DefaultWindowDecorViewHostTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/DefaultWindowDecorViewHostTest.kt
new file mode 100644
index 0000000..2f223de
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/DefaultWindowDecorViewHostTest.kt
@@ -0,0 +1,221 @@
+/*
+ * 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.common.viewhost
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.SurfaceControl
+import android.view.SurfaceControlViewHost
+import android.view.View
+import android.view.WindowManager
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.advanceUntilIdle
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertThrows
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
+
+/**
+ * Tests for [DefaultWindowDecorViewHost].
+ *
+ * Build/Install/Run: atest WMShellUnitTests:DefaultWindowDecorViewHostTest
+ */
+@SmallTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+class DefaultWindowDecorViewHostTest : ShellTestCase() {
+
+    @Test
+    fun updateView_layoutInViewHost() = runTest {
+        val windowDecorViewHost = createDefaultViewHost()
+        val view = View(context)
+
+        windowDecorViewHost.updateView(
+            view = view,
+            attrs = WindowManager.LayoutParams(100, 100),
+            configuration = context.resources.configuration,
+            onDrawTransaction = null,
+        )
+
+        assertThat(windowDecorViewHost.viewHost).isNotNull()
+        assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(view)
+    }
+
+    @Test
+    fun updateView_alreadyLaidOut_relayouts() = runTest {
+        val windowDecorViewHost = createDefaultViewHost()
+        val view = View(context)
+        windowDecorViewHost.updateView(
+            view = view,
+            attrs = WindowManager.LayoutParams(100, 100),
+            configuration = context.resources.configuration,
+            onDrawTransaction = null,
+        )
+
+        val otherParams = WindowManager.LayoutParams(200, 200)
+        windowDecorViewHost.updateView(
+            view = view,
+            attrs = otherParams,
+            configuration = context.resources.configuration,
+            onDrawTransaction = null,
+        )
+
+        assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(view)
+        assertThat(windowDecorViewHost.viewHost!!.view!!.layoutParams.width)
+            .isEqualTo(otherParams.width)
+    }
+
+    @Test
+    fun updateView_replacingView_throws() = runTest {
+        val windowDecorViewHost = createDefaultViewHost()
+        val view = View(context)
+        windowDecorViewHost.updateView(
+            view = view,
+            attrs = WindowManager.LayoutParams(100, 100),
+            configuration = context.resources.configuration,
+            onDrawTransaction = null,
+        )
+
+        val otherView = View(context)
+        assertThrows(Exception::class.java) {
+            windowDecorViewHost.updateView(
+                view = otherView,
+                attrs = WindowManager.LayoutParams(100, 100),
+                configuration = context.resources.configuration,
+                onDrawTransaction = null,
+            )
+        }
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    fun updateView_clearsPendingAsyncJob() = runTest {
+        val windowDecorViewHost = createDefaultViewHost()
+        val asyncView = View(context)
+        val syncView = View(context)
+        val asyncAttrs = WindowManager.LayoutParams(100, 100)
+        val syncAttrs = WindowManager.LayoutParams(200, 200)
+
+        windowDecorViewHost.updateViewAsync(
+            view = asyncView,
+            attrs = asyncAttrs,
+            configuration = context.resources.configuration,
+        )
+
+        // No view host yet, since the coroutine hasn't run.
+        assertThat(windowDecorViewHost.viewHost).isNull()
+
+        windowDecorViewHost.updateView(
+            view = syncView,
+            attrs = syncAttrs,
+            configuration = context.resources.configuration,
+            onDrawTransaction = null,
+        )
+
+        // Would run coroutine if it hadn't been cancelled.
+        advanceUntilIdle()
+
+        assertThat(windowDecorViewHost.viewHost).isNotNull()
+        assertThat(windowDecorViewHost.viewHost!!.view).isNotNull()
+        // View host view/attrs should match the ones from the sync call, plus, since the
+        // sync/async were made with different views, if the job hadn't been cancelled there
+        // would've been an exception thrown as replacing views isn't allowed.
+        assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(syncView)
+        assertThat(windowDecorViewHost.viewHost!!.view!!.layoutParams.width)
+            .isEqualTo(syncAttrs.width)
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    fun updateViewAsync() = runTest {
+        val windowDecorViewHost = createDefaultViewHost()
+        val view = View(context)
+        val attrs = WindowManager.LayoutParams(100, 100)
+
+        windowDecorViewHost.updateViewAsync(
+            view = view,
+            attrs = attrs,
+            configuration = context.resources.configuration,
+        )
+
+        assertThat(windowDecorViewHost.viewHost).isNull()
+
+        advanceUntilIdle()
+
+        assertThat(windowDecorViewHost.viewHost).isNotNull()
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    fun updateViewAsync_clearsPendingAsyncJob() = runTest {
+        val windowDecorViewHost = createDefaultViewHost()
+
+        val view = View(context)
+        windowDecorViewHost.updateViewAsync(
+            view = view,
+            attrs = WindowManager.LayoutParams(100, 100),
+            configuration = context.resources.configuration,
+        )
+        val otherView = View(context)
+        windowDecorViewHost.updateViewAsync(
+            view = otherView,
+            attrs = WindowManager.LayoutParams(100, 100),
+            configuration = context.resources.configuration,
+        )
+
+        advanceUntilIdle()
+
+        assertThat(windowDecorViewHost.viewHost).isNotNull()
+        assertThat(windowDecorViewHost.viewHost!!.view).isNotNull()
+        assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(otherView)
+    }
+
+    @Test
+    fun release() = runTest {
+        val windowDecorViewHost = createDefaultViewHost()
+
+        val view = View(context)
+        windowDecorViewHost.updateView(
+            view = view,
+            attrs = WindowManager.LayoutParams(100, 100),
+            configuration = context.resources.configuration,
+            onDrawTransaction = null,
+        )
+
+        val t = mock(SurfaceControl.Transaction::class.java)
+        windowDecorViewHost.release(t)
+
+        verify(windowDecorViewHost.viewHost!!).release()
+        verify(t).remove(windowDecorViewHost.surfaceControl)
+    }
+
+    private fun CoroutineScope.createDefaultViewHost() =
+        DefaultWindowDecorViewHost(
+            context = context,
+            mainScope = this,
+            display = context.display,
+            surfaceControlViewHostFactory = { c, d, wwm, s ->
+                spy(SurfaceControlViewHost(c, d, wwm, s))
+            },
+        )
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModelTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModelTest.kt
index d8c1a11..193c2c2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModelTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModelTest.kt
@@ -25,9 +25,9 @@
 import com.android.wm.shell.common.DisplayController
 import com.android.wm.shell.common.SyncTransactionQueue
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger
-import com.android.wm.shell.desktopmode.DesktopRepository
+import com.android.wm.shell.desktopmode.DesktopUserRepositories
 import com.android.wm.shell.desktopmode.DesktopTasksController
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
 import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator
 import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler
 import com.android.wm.shell.transition.Transitions
@@ -52,7 +52,7 @@
     private val syncQueueMock: SyncTransactionQueue = mock()
     private val transitionsMock: Transitions = mock()
     private val shellTaskOrganizerMock: ShellTaskOrganizer = mock()
-    private val desktopRepository: DesktopRepository = mock()
+    private val userRepositories: DesktopUserRepositories = mock()
     private val desktopModeEventLogger: DesktopModeEventLogger = mock()
     private val toggleResizeDesktopTaskTransitionHandlerMock:
         ToggleResizeDesktopTaskTransitionHandler =
@@ -75,7 +75,7 @@
                 shellTaskOrganizerMock,
                 toggleResizeDesktopTaskTransitionHandlerMock,
                 returnToDragStartAnimatorMock,
-                desktopRepository,
+                userRepositories,
                 desktopModeEventLogger,
             )
         whenever(contextMock.createContextAsUser(any(), any())).thenReturn(contextMock)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt
index 3143946..121e0e9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt
@@ -122,6 +122,6 @@
 
     companion object {
         private val BOUNDS = Rect(1, 2, 3, 4)
-        private val CORNER_RADIUS = 28
+        private const val CORNER_RADIUS = 28
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt
index ad6fdf4..95e2151 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt
@@ -38,7 +38,8 @@
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
 import com.android.wm.shell.desktopmode.DesktopRepository
 import com.android.wm.shell.desktopmode.DesktopTasksController
-import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopUserRepositories
 import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator
 import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler
 import com.android.wm.shell.transition.Transitions
@@ -93,10 +94,11 @@
     private val transition: IBinder = mock()
     private val info: TransitionInfo = mock()
     private val finishCallback: Transitions.TransitionFinishCallback = mock()
-    private val desktopRepository: DesktopRepository = mock()
+    private val userRepositories: DesktopUserRepositories = mock()
     private val desktopModeEventLogger: DesktopModeEventLogger = mock()
     private val desktopTilingDividerWindowManager: DesktopTilingDividerWindowManager = mock()
     private val motionEvent: MotionEvent = mock()
+    private val desktopRepository: DesktopRepository = mock()
     private lateinit var tilingDecoration: DesktopTilingWindowDecoration
 
     private val split_divider_width = 10
@@ -116,15 +118,16 @@
                 shellTaskOrganizer,
                 toggleResizeDesktopTaskTransitionHandler,
                 returnToDragStartAnimator,
-                desktopRepository,
+                userRepositories,
                 desktopModeEventLogger,
             )
         whenever(context.createContextAsUser(any(), any())).thenReturn(context)
+        whenever(userRepositories.current).thenReturn(desktopRepository)
     }
 
     @Test
     fun taskTiled_toCorrectBounds_leftTile() {
-        val task1 = createFreeformTask()
+        val task1 = createVisibleTask()
         val stableBounds = STABLE_BOUNDS_MOCK
         whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
         whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -151,7 +154,7 @@
     @Test
     fun taskTiled_toCorrectBounds_rightTile() {
         // Setup
-        val task1 = createFreeformTask()
+        val task1 = createVisibleTask()
         val stableBounds = STABLE_BOUNDS_MOCK
         whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
         whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -177,7 +180,7 @@
 
     @Test
     fun taskTiled_notAnimated_whenTilingPositionNotChange() {
-        val task1 = createFreeformTask()
+        val task1 = createVisibleTask()
         val stableBounds = STABLE_BOUNDS_MOCK
         whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
         whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -213,8 +216,8 @@
 
     @Test
     fun taskNotTiled_notBroughtToFront_tilingNotInitialised() {
-        val task1 = createFreeformTask()
-        val task2 = createFreeformTask()
+        val task1 = createVisibleTask()
+        val task2 = createVisibleTask()
         val stableBounds = STABLE_BOUNDS_MOCK
         whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
         whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -236,9 +239,9 @@
 
     @Test
     fun taskNotTiled_notBroughtToFront_taskNotTiled() {
-        val task1 = createFreeformTask()
-        val task2 = createFreeformTask()
-        val task3 = createFreeformTask()
+        val task1 = createVisibleTask()
+        val task2 = createVisibleTask()
+        val task3 = createVisibleTask()
         val stableBounds = STABLE_BOUNDS_MOCK
         whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
         whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -265,9 +268,9 @@
     }
 
     @Test
-    fun taskTiled_broughtToFront_alreadyInFrontNoAction() {
-        val task1 = createFreeformTask()
-        val task2 = createFreeformTask()
+    fun taskTiled_broughtToFront_alreadyInFrontStillReorder() {
+        val task1 = createVisibleTask()
+        val task2 = createVisibleTask()
         val stableBounds = STABLE_BOUNDS_MOCK
         whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
         whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -275,6 +278,8 @@
         }
         whenever(context.resources).thenReturn(resources)
         whenever(resources.getDimensionPixelSize(any())).thenReturn(split_divider_width)
+        whenever(userRepositories.current.isVisibleTask(eq(task1.taskId))).thenReturn(true)
+        whenever(userRepositories.current.isVisibleTask(eq(task2.taskId))).thenReturn(true)
 
         tilingDecoration.onAppTiled(
             task1,
@@ -290,15 +295,15 @@
         )
         task1.isFocused = true
 
-        assertThat(tilingDecoration.moveTiledPairToFront(task1)).isFalse()
-        verify(transitions, never()).startTransition(any(), any(), any())
+        assertThat(tilingDecoration.moveTiledPairToFront(task1, isTaskFocused = true)).isTrue()
+        verify(transitions, times(1)).startTransition(eq(TRANSIT_TO_FRONT), any(), eq(null))
     }
 
     @Test
     fun taskTiled_broughtToFront_bringToFront() {
-        val task1 = createFreeformTask()
-        val task2 = createFreeformTask()
-        val task3 = createFreeformTask()
+        val task1 = createVisibleTask()
+        val task2 = createVisibleTask()
+        val task3 = createVisibleTask()
         val stableBounds = STABLE_BOUNDS_MOCK
         whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
             (i.arguments.first() as Rect).set(stableBounds)
@@ -306,7 +311,7 @@
         whenever(context.resources).thenReturn(resources)
         whenever(resources.getDimensionPixelSize(any())).thenReturn(split_divider_width)
         whenever(desktopWindowDecoration.getLeash()).thenReturn(surfaceControlMock)
-        whenever(desktopRepository.isVisibleTask(any())).thenReturn(true)
+        whenever(userRepositories.current.isVisibleTask(any())).thenReturn(true)
         tilingDecoration.onAppTiled(
             task1,
             desktopWindowDecoration,
@@ -329,9 +334,9 @@
 
     @Test
     fun taskTiled_broughtToFront_taskInfoNotUpdated_bringToFront() {
-        val task1 = createFreeformTask()
-        val task2 = createFreeformTask()
-        val task3 = createFreeformTask()
+        val task1 = createVisibleTask()
+        val task2 = createVisibleTask()
+        val task3 = createVisibleTask()
         val stableBounds = STABLE_BOUNDS_MOCK
         whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
             (i.arguments.first() as Rect).set(stableBounds)
@@ -339,7 +344,7 @@
         whenever(context.resources).thenReturn(resources)
         whenever(resources.getDimensionPixelSize(any())).thenReturn(split_divider_width)
         whenever(desktopWindowDecoration.getLeash()).thenReturn(surfaceControlMock)
-        whenever(desktopRepository.isVisibleTask(any())).thenReturn(true)
+        whenever(userRepositories.current.isVisibleTask(any())).thenReturn(true)
         tilingDecoration.onAppTiled(
             task1,
             desktopWindowDecoration,
@@ -361,8 +366,8 @@
     @Test
     fun taskTiledTasks_NotResized_BeforeTouchEndArrival() {
         // Setup
-        val task1 = createFreeformTask()
-        val task2 = createFreeformTask()
+        val task1 = createVisibleTask()
+        val task2 = createVisibleTask()
         val stableBounds = STABLE_BOUNDS_MOCK
         whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
         whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -428,8 +433,8 @@
     @Test
     fun tiledTasksResizedUsingDividerHandle_shouldLogResizingEvents() {
         // Setup
-        val task1 = createFreeformTask()
-        val task2 = createFreeformTask()
+        val task1 = createVisibleTask()
+        val task2 = createVisibleTask()
         val stableBounds = STABLE_BOUNDS_MOCK
         whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
         whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -487,7 +492,7 @@
 
     @Test
     fun taskTiled_shouldBeRemoved_whenTileBroken() {
-        val task1 = createFreeformTask()
+        val task1 = createVisibleTask()
         val stableBounds = STABLE_BOUNDS_MOCK
         whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
         whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -516,8 +521,8 @@
 
     @Test
     fun taskNotTiled_shouldNotBeRemoved_whenNotTiled() {
-        val task1 = createFreeformTask()
-        val task2 = createFreeformTask()
+        val task1 = createVisibleTask()
+        val task2 = createVisibleTask()
         val stableBounds = STABLE_BOUNDS_MOCK
         whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
         whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -545,8 +550,8 @@
 
     @Test
     fun tasksTiled_shouldBeRemoved_whenSessionDestroyed() {
-        val task1 = createFreeformTask()
-        val task2 = createFreeformTask()
+        val task1 = createVisibleTask()
+        val task2 = createVisibleTask()
         val stableBounds = STABLE_BOUNDS_MOCK
         whenever(displayController.getDisplayLayout(any())).thenReturn(displayLayout)
         whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
@@ -610,6 +615,11 @@
         return Rect(stableBounds.left, stableBounds.top, rightBound, stableBounds.bottom)
     }
 
+    private fun createVisibleTask() =
+        createFreeformTask().also {
+            whenever(userRepositories.current.isVisibleTask(eq(it.taskId))).thenReturn(true)
+        }
+
     companion object {
         private val NON_STABLE_BOUNDS_MOCK = Rect(50, 55, 100, 100)
         private val STABLE_BOUNDS_MOCK = Rect(0, 0, 100, 100)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/TilingDividerViewTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/TilingDividerViewTest.kt
index 734815c..9a9d05a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/TilingDividerViewTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/TilingDividerViewTest.kt
@@ -19,9 +19,12 @@
 import android.graphics.Rect
 import android.os.SystemClock
 import android.testing.AndroidTestingRunner
+import android.util.Size
+import android.view.Display
 import android.view.InputDevice
 import android.view.LayoutInflater
 import android.view.MotionEvent
+import android.view.RoundedCorner
 import android.view.View
 import androidx.test.annotation.UiThreadTest
 import androidx.test.filters.SmallTest
@@ -46,16 +49,19 @@
     private val dividerMoveCallbackMock = mock<DividerMoveCallback>()
 
     private val viewMock = mock<View>()
+    private val display = mock<Display>()
+    private val roundedCorner = mock<RoundedCorner>()
 
     @Before
     @UiThreadTest
     fun setUp() {
+        whenever(display.getRoundedCorner(any())).thenReturn(roundedCorner)
+        whenever(roundedCorner.radius).thenReturn(CORNER_RADIUS)
         tilingDividerView =
             LayoutInflater.from(mContext).inflate(R.layout.tiling_split_divider, /* root= */ null)
                 as TilingDividerView
-        tilingDividerView.setup(dividerMoveCallbackMock, BOUNDS)
-        tilingDividerView.handleStartY = 0
-        tilingDividerView.handleEndY = 1500
+        tilingDividerView.setup(dividerMoveCallbackMock, DIVIDER_BOUNDS, HANDLE_SIZE)
+        tilingDividerView.handleY = 0..1500
     }
 
     @Test
@@ -130,6 +136,8 @@
     }
 
     companion object {
-        private val BOUNDS = Rect(0, 0, 1500, 1500)
+        private val DIVIDER_BOUNDS = Rect(15, 0, 35, 1500)
+        private val HANDLE_SIZE = Size(800, 300)
+        private const val CORNER_RADIUS = 15
     }
 }
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
index e5fb755..7b45070 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -48,7 +48,14 @@
     minikinPaint.localeListId = paint->getMinikinLocaleListId();
     minikinPaint.fontStyle = resolvedFace->fStyle;
     minikinPaint.fontFeatureSettings = paint->getFontFeatureSettings();
-    minikinPaint.fontVariationSettings = paint->getFontVariationOverride();
+    if (!resolvedFace->fIsVariationInstance) {
+        // This is an optimization for direct private API use typically done by System UI.
+        // In the public API surface, if Typeface is already configured for variation instance
+        // (Target SDK <= 35) the font variation settings of Paint is not set.
+        // On the other hand, if Typeface is not configured so (Target SDK >= 36), the font
+        // variation settings are configured dynamically.
+        minikinPaint.fontVariationSettings = paint->getFontVariationOverride();
+    }
     minikinPaint.verticalText = paint->isVerticalText();
 
     const std::optional<minikin::FamilyVariant>& familyVariant = paint->getFamilyVariant();
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index 2d812d6..4dfe053 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -76,6 +76,7 @@
         result->fBaseWeight = resolvedFace->fBaseWeight;
         result->fAPIStyle = style;
         result->fStyle = computeRelativeStyle(result->fBaseWeight, style);
+        result->fIsVariationInstance = resolvedFace->fIsVariationInstance;
     }
     return result;
 }
@@ -88,6 +89,7 @@
         result->fBaseWeight = resolvedFace->fBaseWeight;
         result->fAPIStyle = computeAPIStyle(weight, italic);
         result->fStyle = computeMinikinStyle(weight, italic);
+        result->fIsVariationInstance = resolvedFace->fIsVariationInstance;
     }
     return result;
 }
@@ -109,6 +111,7 @@
         result->fBaseWeight = resolvedFace->fBaseWeight;
         result->fAPIStyle = resolvedFace->fAPIStyle;
         result->fStyle = resolvedFace->fStyle;
+        result->fIsVariationInstance = true;
     }
     return result;
 }
@@ -121,6 +124,7 @@
         result->fBaseWeight = weight;
         result->fAPIStyle = resolvedFace->fAPIStyle;
         result->fStyle = computeRelativeStyle(weight, result->fAPIStyle);
+        result->fIsVariationInstance = resolvedFace->fIsVariationInstance;
     }
     return result;
 }
@@ -170,6 +174,7 @@
     result->fBaseWeight = weight;
     result->fAPIStyle = computeAPIStyle(weight, italic);
     result->fStyle = computeMinikinStyle(weight, italic);
+    result->fIsVariationInstance = false;
     return result;
 }
 
diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h
index 2c96c1a..97d1bf4 100644
--- a/libs/hwui/hwui/Typeface.h
+++ b/libs/hwui/hwui/Typeface.h
@@ -44,6 +44,9 @@
     // base weight in CSS-style units, 1..1000
     int fBaseWeight;
 
+    // True if the Typeface is already created for variation settings.
+    bool fIsVariationInstance;
+
     static const Typeface* resolveDefault(const Typeface* src);
 
     // The following three functions create new Typeface from an existing Typeface with a different
diff --git a/libs/hwui/jni/ColorFilter.cpp b/libs/hwui/jni/ColorFilter.cpp
index 20301d2..1c6d886 100644
--- a/libs/hwui/jni/ColorFilter.cpp
+++ b/libs/hwui/jni/ColorFilter.cpp
@@ -163,6 +163,20 @@
             filter->updateChild(env, name.c_str(), child);
         }
     }
+
+    static void RuntimeColorFilter_updateInputColorFilter(JNIEnv* env, jobject,
+                                                          jlong colorFilterPtr, jstring childName,
+                                                          jlong childFilterPtr) {
+        auto* filter = reinterpret_cast<RuntimeColorFilter*>(colorFilterPtr);
+        ScopedUtfChars name(env, childName);
+        auto* child = reinterpret_cast<ColorFilter*>(childFilterPtr);
+        if (filter && child) {
+            auto childInput = child->getInstance();
+            if (childInput) {
+                filter->updateChild(env, name.c_str(), childInput.release());
+            }
+        }
+    }
 };
 
 static const JNINativeMethod colorfilter_methods[] = {
@@ -193,7 +207,9 @@
         {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V",
          (void*)ColorFilterGlue::RuntimeColorFilter_updateUniformsInts},
         {"nativeUpdateChild", "(JLjava/lang/String;J)V",
-         (void*)ColorFilterGlue::RuntimeColorFilter_updateChild}};
+         (void*)ColorFilterGlue::RuntimeColorFilter_updateChild},
+        {"nativeUpdateInputColorFilter", "(JLjava/lang/String;J)V",
+         (void*)ColorFilterGlue::RuntimeColorFilter_updateInputColorFilter}};
 
 int register_android_graphics_ColorFilter(JNIEnv* env) {
     android::RegisterMethodsOrDie(env, "android/graphics/ColorFilter", colorfilter_methods,
diff --git a/libs/hwui/jni/RuntimeXfermode.cpp b/libs/hwui/jni/RuntimeXfermode.cpp
index c1c8964..17bee8f 100644
--- a/libs/hwui/jni/RuntimeXfermode.cpp
+++ b/libs/hwui/jni/RuntimeXfermode.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "ColorFilter.h"
 #include "GraphicsJNI.h"
 #include "RuntimeEffectUtils.h"
 #include "SkBlender.h"
@@ -93,6 +94,19 @@
     }
 }
 
+static void RuntimeXfermode_updateColorFilter(JNIEnv* env, jobject, jlong builderPtr,
+                                              jstring childName, jlong colorFilterPtr) {
+    auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr);
+    ScopedUtfChars name(env, childName);
+    auto* child = reinterpret_cast<ColorFilter*>(colorFilterPtr);
+    if (child) {
+        auto childInput = child->getInstance();
+        if (childInput) {
+            UpdateChild(env, builder, name.c_str(), childInput.release());
+        }
+    }
+}
+
 static const JNINativeMethod gRuntimeXfermodeMethods[] = {
         {"nativeGetFinalizer", "()J", (void*)RuntimeXfermode_getNativeFinalizer},
         {"nativeCreateBlenderBuilder", "(Ljava/lang/String;)J",
@@ -107,6 +121,8 @@
         {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V",
          (void*)RuntimeXfermode_updateIntUniforms},
         {"nativeUpdateChild", "(JLjava/lang/String;J)V", (void*)RuntimeXfermode_updateChild},
+        {"nativeUpdateColorFilter", "(JLjava/lang/String;J)V",
+         (void*)RuntimeXfermode_updateColorFilter},
 };
 
 int register_android_graphics_RuntimeXfermode(JNIEnv* env) {
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index 018c2b13..eadb9de 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -1,5 +1,6 @@
 #include <vector>
 
+#include "ColorFilter.h"
 #include "Gainmap.h"
 #include "GraphicsJNI.h"
 #include "RuntimeEffectUtils.h"
@@ -331,6 +332,15 @@
     builder->child(name.c_str()) = sk_ref_sp(shader);
 }
 
+static void RuntimeShader_updateColorFilter(JNIEnv* env, jobject, jlong shaderBuilder,
+                                            jstring jUniformName, jlong colorFilterHandle) {
+    SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
+    ScopedUtfChars name(env, jUniformName);
+    auto* childEffect = reinterpret_cast<ColorFilter*>(colorFilterHandle);
+
+    UpdateChild(env, builder, name.c_str(), childEffect->getInstance().release());
+}
+
 static void RuntimeShader_updateChild(JNIEnv* env, jobject, jlong shaderBuilder,
                                       jstring jUniformName, jlong childHandle) {
     SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
@@ -380,6 +390,8 @@
         {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V",
          (void*)RuntimeShader_updateIntUniforms},
         {"nativeUpdateShader", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateShader},
+        {"nativeUpdateColorFilter", "(JLjava/lang/String;J)V",
+         (void*)RuntimeShader_updateColorFilter},
         {"nativeUpdateChild", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateChild},
 };
 
diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp
index d9dc8eb..a0291a9 100644
--- a/libs/hwui/jni/android_graphics_RenderNode.cpp
+++ b/libs/hwui/jni/android_graphics_RenderNode.cpp
@@ -594,14 +594,12 @@
             Matrix4 transform;
             SkIRect clipBounds;
             uirenderer::Rect initialClipBounds;
-            const auto clipFlags = props.getClippingFlags();
             if (enableClip) {
-                if (clipFlags) {
-                    props.getClippingRectForFlags(clipFlags, &initialClipBounds);
-                } else {
-                    // Works for RenderNode::damageSelf()
-                    initialClipBounds.set(DIRTY_MIN, DIRTY_MIN, DIRTY_MAX, DIRTY_MAX);
-                }
+                // SurfaceView never draws beyond its bounds regardless of if it can or not,
+                // so if clip-to-bounds is disabled just use the bounds as the starting point
+                // regardless
+                const auto clipFlags = props.getClippingFlags();
+                props.getClippingRectForFlags(clipFlags | CLIP_TO_BOUNDS, &initialClipBounds);
                 clipBounds =
                         info.damageAccumulator
                                 ->computeClipAndTransform(initialClipBounds.toSkRect(), &transform)
diff --git a/libs/hwui/jni/text/TextShaper.cpp b/libs/hwui/jni/text/TextShaper.cpp
index 5f69346..c735989 100644
--- a/libs/hwui/jni/text/TextShaper.cpp
+++ b/libs/hwui/jni/text/TextShaper.cpp
@@ -68,7 +68,7 @@
 static jlong shapeTextRun(const uint16_t* text, int textSize, int start, int count,
     int contextStart, int contextCount, minikin::Bidi bidiFlags,
     const Paint& paint, const Typeface* typeface) {
-
+    const Typeface* resolvedFace = Typeface::resolveDefault(typeface);
     minikin::MinikinPaint minikinPaint = MinikinUtils::prepareMinikinPaint(&paint, typeface);
 
     minikin::Layout layout = MinikinUtils::doLayout(&paint, bidiFlags, typeface,
@@ -103,8 +103,16 @@
                 fontId = it->second;  // We've seen it.
             } else {
                 fontId = fonts.size();  // This is new to us. Create new one.
-                std::shared_ptr<minikin::Font> font = std::make_shared<minikin::Font>(
-                        fakedFont.font, fakedFont.fakery.variationSettings());
+                std::shared_ptr<minikin::Font> font;
+                if (resolvedFace->fIsVariationInstance) {
+                    // The optimization for target SDK 35 or before because the variation instance
+                    // is already created and no runtime variation resolution happens on such
+                    // environment.
+                    font = fakedFont.font;
+                } else {
+                    font = std::make_shared<minikin::Font>(fakedFont.font,
+                                                           fakedFont.fakery.variationSettings());
+                }
                 fonts.push_back(reinterpret_cast<jlong>(new FontWrapper(std::move(font))));
                 fakedToFontIds.insert(std::make_pair(fakedFont, fontId));
             }
diff --git a/location/java/android/location/altitude/AltitudeConverter.java b/location/java/android/location/altitude/AltitudeConverter.java
index b9fe804..3a4e70d 100644
--- a/location/java/android/location/altitude/AltitudeConverter.java
+++ b/location/java/android/location/altitude/AltitudeConverter.java
@@ -26,8 +26,8 @@
 import android.location.flags.Flags;
 
 import com.android.internal.location.altitude.GeoidMap;
-import com.android.internal.location.altitude.S2CellIdUtils;
 import com.android.internal.location.altitude.nano.MapParamsProto;
+import com.android.internal.location.geometry.S2CellIdUtils;
 import com.android.internal.util.Preconditions;
 
 import java.io.IOException;
diff --git a/location/java/com/android/internal/location/altitude/GeoidMap.java b/location/java/com/android/internal/location/altitude/GeoidMap.java
index df9ca97..d77fb9e 100644
--- a/location/java/com/android/internal/location/altitude/GeoidMap.java
+++ b/location/java/com/android/internal/location/altitude/GeoidMap.java
@@ -26,6 +26,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.location.altitude.nano.MapParamsProto;
 import com.android.internal.location.altitude.nano.S2TileProto;
+import com.android.internal.location.geometry.S2CellIdUtils;
 import com.android.internal.util.Preconditions;
 
 import java.io.IOException;
diff --git a/location/java/com/android/internal/location/altitude/S2CellIdUtils.java b/location/java/com/android/internal/location/geometry/S2CellIdUtils.java
similarity index 80%
rename from location/java/com/android/internal/location/altitude/S2CellIdUtils.java
rename to location/java/com/android/internal/location/geometry/S2CellIdUtils.java
index 08bcda4..fbdaf49 100644
--- a/location/java/com/android/internal/location/altitude/S2CellIdUtils.java
+++ b/location/java/com/android/internal/location/geometry/S2CellIdUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.location.altitude;
+package com.android.internal.location.geometry;
 
 import android.annotation.NonNull;
 
@@ -48,12 +48,22 @@
     private static final double UV_LIMIT = calculateUvLimit();
     private static final UvTransform[] UV_TRANSFORMS = createUvTransforms();
     private static final XyzTransform[] XYZ_TRANSFORMS = createXyzTransforms();
+    private static final long MAX_SI_TI = 1L << (MAX_LEVEL + 1);
 
     // Used to encode (i, j, o) coordinates into primitive longs.
     private static final int I_SHIFT = 33;
     private static final int J_SHIFT = 2;
     private static final long J_MASK = (1L << 31) - 1;
 
+    // Used to insert latitude and longitude values into arrays.
+    public static final int LAT_LNG_MIN_LENGTH = 2;
+    public static final int LAT_INDEX = 0;
+    public static final int LNG_INDEX = 1;
+
+    // Used to encode (si, ti) coordinates into primitive longs.
+    private static final int SI_SHIFT = 32;
+    private static final long TI_MASK = (1L << 32) - 1;
+
     static {
         initLookupCells();
     }
@@ -63,6 +73,130 @@
     }
 
     /**
+     * Inserts into {@code latLngDegrees} the centroid latitude and longitude, in that order and
+     * both measured in degrees, for the specified S2 cell ID. This array must be non-null and of
+     * minimum length two. A reference to this array is returned.
+     *
+     * <p>Behavior is undefined for invalid S2 cell IDs.
+     */
+    public static double[] toLatLngDegrees(long s2CellId, double[] latLngDegrees) {
+        // Used latLngDegrees as scratchpad for toLatLngRadians(long, double[]).
+        final double[] latLngRadians = latLngDegrees;
+        toLatLngRadians(s2CellId, latLngRadians);
+        latLngDegrees[LAT_INDEX] = Math.toDegrees(latLngRadians[LAT_INDEX]);
+        latLngDegrees[LNG_INDEX] = Math.toDegrees(latLngRadians[LNG_INDEX]);
+        return latLngDegrees;
+    }
+
+
+    /**
+     * Inserts into {@code latLngRadians} the centroid latitude and longitude, in that order and
+     * both measured in radians, for the specified S2 cell ID. This array must be non-null and of
+     * minimum length two. A reference to this array is returned.
+     *
+     * <p>Behavior is undefined for invalid S2 cell IDs.
+     */
+    public static double[] toLatLngRadians(long s2CellId, double[] latLngRadians) {
+        checkNotNull(latLngRadians);
+        checkLengthGreaterThanOrEqualTo(LAT_LNG_MIN_LENGTH, latLngRadians.length);
+
+        final long siTi = toSiTi(s2CellId);
+        final double u = siTiToU(siTi);
+        final double v = siTiToV(siTi);
+
+        final int face = getFace(s2CellId);
+        final XyzTransform xyzTransform = faceToXyzTransform(face);
+        final double x = xyzTransform.uvToX(u, v);
+        final double y = xyzTransform.uvToY(u, v);
+        final double z = xyzTransform.uvToZ(u, v);
+
+        latLngRadians[LAT_INDEX] = xyzToLatRadians(x, y, z);
+        latLngRadians[LNG_INDEX] = xyzToLngRadians(x, y);
+        return latLngRadians;
+    }
+
+    private static long toSiTi(long s2CellId) {
+        final long ijo = toIjo(s2CellId);
+        final int i = ijoToI(ijo);
+        final int j = ijoToJ(ijo);
+        int delta = isLeaf(s2CellId) ? 1 : (((i ^ (((int) s2CellId) >>> 2)) & 1) != 0) ? 2 : 0;
+        return (((long) (2 * i + delta)) << SI_SHIFT) | ((2 * j + delta) & TI_MASK);
+    }
+
+    private static int siTiToSi(long siTi) {
+        return (int) (siTi >> SI_SHIFT);
+    }
+
+    private static int siTiToTi(long siTi) {
+        return (int) siTi;
+    }
+
+    private static double siTiToU(long siTi) {
+        final int si = siTiToSi(siTi);
+        return siToU(si);
+    }
+
+    private static double siTiToV(long siTi) {
+        final int ti = siTiToTi(siTi);
+        return tiToV(ti);
+    }
+
+    private static double siToU(long si) {
+        final double s = (1.0 / MAX_SI_TI) * si;
+        if (s >= 0.5) {
+            return (1 / 3.) * (4 * s * s - 1);
+        }
+        return (1 / 3.) * (1 - 4 * (1 - s) * (1 - s));
+    }
+
+    private static double tiToV(long ti) {
+        // Same calculation as siToU.
+        return siToU(ti);
+    }
+
+    private static XyzTransform faceToXyzTransform(int face) {
+        // We map illegal face indices to the largest face index to preserve legacy behavior, i.e.,
+        // we do not want to throw an index out of bounds exception. Note that getFace(s2CellId) is
+        // guaranteed to return a non-negative face index even for invalid S2 cells, so it is
+        // sufficient to just map all face indices greater than the largest face index to the
+        // largest face index.
+        return XYZ_TRANSFORMS[Math.min(NUM_FACES - 1, face)];
+    }
+
+    private static double xyzToLngRadians(double x, double y) {
+        return Math.atan2(y, x);
+    }
+
+    private static double xyzToLatRadians(double x, double y, double z) {
+        return Math.atan2(z, Math.sqrt(x * x + y * y));
+    }
+
+    private static void checkNotNull(Object object) {
+        if (object == null) {
+            throw new NullPointerException("Given array cannot be null.");
+        }
+    }
+
+    private static void checkLengthGreaterThanOrEqualTo(int minLength, int actualLength) {
+        if (actualLength < minLength) {
+            throw new IllegalArgumentException(
+                "Given array of length " + actualLength + " needs to be of minimum length "
+                + minLength);
+        }
+    }
+
+    /**
+     * Returns true if the provided S2 cell contains the provided latitude/longitude, both measured
+     * in degrees.
+     */
+    public static boolean containsLatLngDegrees(long s2CellId, double latDegrees,
+            double lngDegrees) {
+        int level = getLevel(s2CellId);
+        long leafCellId = fromLatLngDegrees(latDegrees, lngDegrees);
+        return (getParent(leafCellId, level) == s2CellId);
+    }
+
+    /**
      * Returns the leaf S2 cell ID for the specified latitude and longitude, both measured in
      * degrees.
      */
@@ -176,7 +310,7 @@
      * Returns the level of the specified S2 cell. The returned level is in [0, 30] for valid
      * S2 cell IDs. Behavior is undefined for invalid S2 cell IDs.
      */
-    static int getLevel(long s2CellId) {
+    public static int getLevel(long s2CellId) {
         if (isLeaf(s2CellId)) {
             return MAX_LEVEL;
         }
@@ -197,12 +331,12 @@
      * Returns the ID of the first S2 cell in a traversal of the children S2 cells at the specified
      * level, in Hilbert curve order.
      */
-    static long getTraversalStart(long s2CellId, int level) {
+    public static long getTraversalStart(long s2CellId, int level) {
         return s2CellId - getLowestOnBit(s2CellId) + getLowestOnBitForLevel(level);
     }
 
     /** Returns the ID of the next S2 cell at the same level along the Hilbert curve. */
-    static long getTraversalNext(long s2CellId) {
+    public static long getTraversalNext(long s2CellId) {
         return s2CellId + (getLowestOnBit(s2CellId) << 1);
     }
 
@@ -211,7 +345,7 @@
      * lower levels (i.e., larger cells) are encoded into fewer characters.
      */
     @NonNull
-    static String getToken(long s2CellId) {
+    public static String getToken(long s2CellId) {
         if (s2CellId == 0) {
             return "X";
         }
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index c085b89..dba9cc9 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -283,8 +283,19 @@
      * Flag used when playback is muted by AppOpsManager#OP_PLAY_AUDIO.
      */
     @SystemApi
+    @FlaggedApi(FLAG_MUTED_BY_PORT_VOLUME_API)
     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
-    public static final int MUTED_BY_APP_OPS = (1 << 3);
+    public static final int MUTED_BY_OP_PLAY_AUDIO = (1 << 3);
+    /**
+     * @hide
+     * Flag used when playback is muted by AppOpsManager#OP_PLAY_AUDIO.
+     * @deprecated see {@link MUTED_BY_OP_PLAY_AUDIO}
+     */
+    @SystemApi
+    @Deprecated
+    @FlaggedApi(FLAG_MUTED_BY_PORT_VOLUME_API)
+    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+    public static final int MUTED_BY_APP_OPS = MUTED_BY_OP_PLAY_AUDIO;
     /**
      * @hide
      * Flag used when muted by client volume.
@@ -311,12 +322,21 @@
     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
     public static final int MUTED_BY_PORT_VOLUME = (1 << 6);
 
+    /**
+     * @hide
+     * Flag used when playback is muted by AppOpsManager#OP_CONTROL_AUDIO.
+     */
+    @SystemApi
+    @FlaggedApi(FLAG_MUTED_BY_PORT_VOLUME_API)
+    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+    public static final int MUTED_BY_OP_CONTROL_AUDIO = (1 << 7);
+
     /** @hide */
     @IntDef(
             flag = true,
             value = {MUTED_BY_MASTER, MUTED_BY_STREAM_VOLUME, MUTED_BY_STREAM_MUTED,
-                    MUTED_BY_APP_OPS, MUTED_BY_CLIENT_VOLUME, MUTED_BY_VOLUME_SHAPER,
-                    MUTED_BY_PORT_VOLUME})
+                    MUTED_BY_OP_PLAY_AUDIO, MUTED_BY_CLIENT_VOLUME, MUTED_BY_VOLUME_SHAPER,
+                    MUTED_BY_PORT_VOLUME, MUTED_BY_OP_CONTROL_AUDIO})
     @Retention(RetentionPolicy.SOURCE)
     public @interface PlayerMuteEvent {
     }
@@ -761,7 +781,7 @@
     private boolean isMuteAffectingActiveState() {
         return (mMutedState & MUTED_BY_CLIENT_VOLUME) != 0
                 || (mMutedState & MUTED_BY_VOLUME_SHAPER) != 0
-                || (mMutedState & MUTED_BY_APP_OPS) != 0;
+                || (mMutedState & MUTED_BY_OP_PLAY_AUDIO) != 0;
     }
 
     /**
@@ -902,8 +922,8 @@
                 if ((mMutedState & MUTED_BY_STREAM_MUTED) != 0) {
                     apcToString.append("streamMute ");
                 }
-                if ((mMutedState & MUTED_BY_APP_OPS) != 0) {
-                    apcToString.append("appOps ");
+                if ((mMutedState & MUTED_BY_OP_PLAY_AUDIO) != 0) {
+                    apcToString.append("opPlayAudio ");
                 }
                 if ((mMutedState & MUTED_BY_CLIENT_VOLUME) != 0) {
                     apcToString.append("clientVolume ");
@@ -914,6 +934,9 @@
                 if ((mMutedState & MUTED_BY_PORT_VOLUME) != 0) {
                     apcToString.append("portVolume ");
                 }
+                if ((mMutedState & MUTED_BY_OP_CONTROL_AUDIO) != 0) {
+                    apcToString.append("opControlAudio ");
+                }
             }
             apcToString.append(" ").append(mFormatInfo);
         }
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 08b0dd3..54a87ad 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -640,6 +640,9 @@
 
     boolean canBeSpatialized(in AudioAttributes aa, in AudioFormat af);
 
+    /* Returns a List<Integer> */
+    List getSpatializedChannelMasks();
+
     void registerSpatializerCallback(in ISpatializerCallback cb);
 
     void unregisterSpatializerCallback(in ISpatializerCallback cb);
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index 1ecba31..3efb5f9 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -1010,17 +1010,17 @@
      * scenario, when both resource holder and resource challenger have same processId and same
      * priority.
      *
-     * @param resourceHolderRetain Set to {@code true} to allow the resource holder to retain
-     *     ownership, or false to allow the resource challenger to acquire the resource.
-     *     If not explicitly set, resourceHolderRetain is set to {@code false}.
+     *@param enabled Set to {@code true} to allow the resource holder to retain ownership,
+     *     or false to allow the resource challenger to acquire the resource.
+     *     If not explicitly set, enabled is set to {@code false}.
      * @hide
      */
     @FlaggedApi(FLAG_SET_RESOURCE_HOLDER_RETAIN)
     @SystemApi
     @RequiresPermission(android.Manifest.permission.TUNER_RESOURCE_ACCESS)
-    public void setResourceHolderRetain(boolean resourceHolderRetain) {
+    public void setResourceOwnershipRetention(boolean enabled) {
         if (mTunerResourceManager != null) {
-            mTunerResourceManager.setResourceHolderRetain(mClientId, resourceHolderRetain);
+            mTunerResourceManager.setResourceOwnershipRetention(mClientId, enabled);
         }
     }
 
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 4f94c3e..5038754 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -16,12 +16,12 @@
 
 package android.media;
 
-
 import static android.media.audio.Flags.FLAG_IAMF_DEFINITIONS_API;
+import static android.media.codec.Flags.FLAG_APV_SUPPORT;
 import static android.media.codec.Flags.FLAG_IN_PROCESS_SW_AUDIO_CODEC;
 import static android.media.codec.Flags.FLAG_NUM_INPUT_SLOTS;
 import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
-import static android.media.codec.Flags.FLAG_APV_SUPPORT;
+import static android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES;
 
 import static com.android.media.codec.flags.Flags.FLAG_CODEC_IMPORTANCE;
 import static com.android.media.codec.flags.Flags.FLAG_LARGE_AUDIO_FRAME;
@@ -1796,6 +1796,27 @@
     public static final String KEY_NUM_SLOTS = "num-slots";
 
     /**
+     * A key describing the picture profile ID to be applied to {@link MediaCodec}.
+     * <p>
+     * The associated value is a string.
+     * <p>
+     * @see {@link android.media.quality.PictureProfile}
+     * @see {@link android.media.quality.PictureProfile#getProfileId}
+     */
+    @FlaggedApi(FLAG_APPLY_PICTURE_PROFILES)
+    public static final String KEY_PICTURE_PROFILE_ID = "picture-profile-id";
+
+    /**
+     * A key describing the picture profile instance to be applied to {@link MediaCodec}.
+     * <p>
+     * The associated value is an instance of {@link android.media.quality.PictureProfile}.
+     * <p>
+     * @see {@link android.media.quality.PictureProfile}
+     */
+    @FlaggedApi(FLAG_APPLY_PICTURE_PROFILES)
+    public static final String KEY_PICTURE_PROFILE_INSTANCE = "picture-profile-instance";
+
+    /**
      * QpOffsetRect constitutes the metadata required for encoding a region of interest in an
      * image or a video frame. The region of interest is represented by a rectangle. The four
      * integer coordinates of the rectangle are stored in fields left, top, right, bottom.
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 0902278..d433ec87 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -21,6 +21,7 @@
 
 import static com.android.media.flags.Flags.FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER;
 import static com.android.media.flags.Flags.FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES;
+import static com.android.media.flags.Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2;
 import static com.android.media.flags.Flags.FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES;
 import static com.android.media.flags.Flags.FLAG_ENABLE_NEW_WIRED_MEDIA_ROUTE_2_INFO_TYPES;
 
@@ -421,6 +422,51 @@
      */
     public static final int TYPE_GROUP = 2000;
 
+    /** @hide */
+    @IntDef(
+            prefix = {"ROUTING_TYPE_"},
+            value = {
+                FLAG_ROUTING_TYPE_SYSTEM_AUDIO,
+                FLAG_ROUTING_TYPE_SYSTEM_VIDEO,
+                FLAG_ROUTING_TYPE_REMOTE
+            },
+            flag = true)
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RoutingType {}
+
+    /**
+     * Indicates that a route supports routing of the system audio.
+     *
+     * <p>Providers that support this type of routing require the {@link
+     * android.Manifest.permission#MODIFY_AUDIO_ROUTING} permission.
+     */
+    @FlaggedApi(FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
+    public static final int FLAG_ROUTING_TYPE_SYSTEM_AUDIO = 1;
+
+    /**
+     * Indicates that a route supports routing of the system video.
+     *
+     * @hide
+     */
+    // TODO: b/380431086 - Enable this API once we add support for system video routing.
+    @FlaggedApi(FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
+    public static final int FLAG_ROUTING_TYPE_SYSTEM_VIDEO = 1 << 1;
+
+    /**
+     * Indicates that a route supports routing playback to remote routes through control commands.
+     *
+     * <p>This type of routing does not affect affect this system's audio or video, but instead
+     * relies on the device that corresponds to this route to fetch and play the media. It also
+     * requires the media app to take care of initializing and controlling playback.
+     */
+    @FlaggedApi(FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
+    public static final int FLAG_ROUTING_TYPE_REMOTE = 1 << 2;
+
+    private static final int FLAG_ROUTING_TYPE_ALL =
+            FLAG_ROUTING_TYPE_SYSTEM_AUDIO
+                    | FLAG_ROUTING_TYPE_SYSTEM_VIDEO
+                    | FLAG_ROUTING_TYPE_REMOTE;
+
     /**
      * Route feature: Live audio.
      * <p>
@@ -553,6 +599,7 @@
     private final List<String> mFeatures;
     @Type
     private final int mType;
+    @RoutingType private final int mRoutingTypeFlags;
     private final boolean mIsSystem;
     private final Uri mIconUri;
     private final CharSequence mDescription;
@@ -576,6 +623,7 @@
         mName = builder.mName;
         mFeatures = builder.mFeatures;
         mType = builder.mType;
+        mRoutingTypeFlags = builder.mRoutingTypeFlags;
         mIsSystem = builder.mIsSystem;
         mIconUri = builder.mIconUri;
         mDescription = builder.mDescription;
@@ -600,6 +648,7 @@
         mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
         mFeatures = in.createStringArrayList();
         mType = in.readInt();
+        mRoutingTypeFlags = validateRoutingTypeFlags(in.readInt());
         mIsSystem = in.readBoolean();
         mIconUri = in.readParcelable(null, android.net.Uri.class);
         mDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
@@ -660,6 +709,13 @@
         return mType;
     }
 
+    /** Returns the flags that indicate the routing types supported by this route. */
+    @RoutingType
+    @FlaggedApi(FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
+    public int getSupportedRoutingTypes() {
+        return mRoutingTypeFlags;
+    }
+
     /**
      * Returns whether the route is a system route or not.
      * <p>
@@ -904,6 +960,7 @@
         pw.println(indent + "mName=" + mName);
         pw.println(indent + "mFeatures=" + mFeatures);
         pw.println(indent + "mType=" + getDeviceTypeString(mType));
+        pw.println(indent + "mRoutingTypeFlags=" + getRoutingTypeFlagsString(mRoutingTypeFlags));
         pw.println(indent + "mIsSystem=" + mIsSystem);
         pw.println(indent + "mIconUri=" + mIconUri);
         pw.println(indent + "mDescription=" + mDescription);
@@ -941,6 +998,7 @@
                 && Objects.equals(mName, other.mName)
                 && Objects.equals(mFeatures, other.mFeatures)
                 && (mType == other.mType)
+                && (mRoutingTypeFlags == other.mRoutingTypeFlags)
                 && (mIsSystem == other.mIsSystem)
                 && Objects.equals(mIconUri, other.mIconUri)
                 && Objects.equals(mDescription, other.mDescription)
@@ -966,6 +1024,7 @@
                 mName,
                 mFeatures,
                 mType,
+                mRoutingTypeFlags,
                 mIsSystem,
                 mIconUri,
                 mDescription,
@@ -994,6 +1053,8 @@
                 .append(getName())
                 .append(", type=")
                 .append(getDeviceTypeString(getType()))
+                .append(", routingTypes=")
+                .append(getRoutingTypeFlagsString(getSupportedRoutingTypes()))
                 .append(", isSystem=")
                 .append(isSystemRoute())
                 .append(", features=")
@@ -1035,6 +1096,7 @@
         TextUtils.writeToParcel(mName, dest, flags);
         dest.writeStringList(mFeatures);
         dest.writeInt(mType);
+        dest.writeInt(mRoutingTypeFlags);
         dest.writeBoolean(mIsSystem);
         dest.writeParcelable(mIconUri, flags);
         TextUtils.writeToParcel(mDescription, dest, flags);
@@ -1143,6 +1205,34 @@
         }
     }
 
+    /** Returns a human-readable representation of the given {@code routingTypeFlags}. */
+    private static String getRoutingTypeFlagsString(@RoutingType int routingTypeFlags) {
+        List<String> typeStrings = new ArrayList<>();
+        if ((routingTypeFlags & FLAG_ROUTING_TYPE_SYSTEM_AUDIO) != 0) {
+            typeStrings.add("SYSTEM_AUDIO");
+        }
+        if ((routingTypeFlags & FLAG_ROUTING_TYPE_SYSTEM_VIDEO) != 0) {
+            typeStrings.add("SYSTEM_VIDEO");
+        }
+        if ((routingTypeFlags & FLAG_ROUTING_TYPE_REMOTE) != 0) {
+            typeStrings.add("REMOTE");
+        }
+        return String.join(/* delimiter= */ "|", typeStrings);
+    }
+
+    /**
+     * Throws an {@link IllegalArgumentException} if the provided {@code routingTypeFlags} are not
+     * valid. Otherwise, returns the provided value.
+     */
+    private static int validateRoutingTypeFlags(@RoutingType int routingTypeFlags) {
+        if (routingTypeFlags == 0 || (routingTypeFlags & ~FLAG_ROUTING_TYPE_ALL) != 0) {
+            throw new IllegalArgumentException(
+                    "Invalid routing type flags: " + Integer.toHexString(routingTypeFlags));
+        } else {
+            return routingTypeFlags;
+        }
+    }
+
     /**
      * Builder for {@link MediaRoute2Info media route info}.
      */
@@ -1153,6 +1243,7 @@
 
         @Type
         private int mType = TYPE_UNKNOWN;
+        @RoutingType private int mRoutingTypeFlags = FLAG_ROUTING_TYPE_REMOTE;
         private boolean mIsSystem;
         private Uri mIconUri;
         private CharSequence mDescription;
@@ -1224,6 +1315,7 @@
             mName = routeInfo.mName;
             mFeatures = new ArrayList<>(routeInfo.mFeatures);
             mType = routeInfo.mType;
+            mRoutingTypeFlags = routeInfo.mRoutingTypeFlags;
             mIsSystem = routeInfo.mIsSystem;
             mIconUri = routeInfo.mIconUri;
             mDescription = routeInfo.mDescription;
@@ -1301,6 +1393,18 @@
         }
 
         /**
+         * Sets the routing types that this route supports.
+         *
+         * @see MediaRoute2Info#getSupportedRoutingTypes()
+         */
+        @NonNull
+        @FlaggedApi(FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
+        public Builder setSupportedRoutingTypes(@RoutingType int routingTypeFlags) {
+            mRoutingTypeFlags = validateRoutingTypeFlags(routingTypeFlags);
+            return this;
+        }
+
+        /**
          * Sets whether the route is a system route or not.
          * @hide
          */
diff --git a/media/java/android/media/Spatializer.java b/media/java/android/media/Spatializer.java
index 99fcaf2..95c4ad3 100644
--- a/media/java/android/media/Spatializer.java
+++ b/media/java/android/media/Spatializer.java
@@ -16,7 +16,10 @@
 
 package android.media;
 
+import static android.media.audio.Flags.FLAG_SPATIALIZER_CAPABILITIES;
+
 import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -35,6 +38,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Executor;
@@ -527,6 +531,28 @@
     }
 
     /**
+     * Returns a list of channel masks that represent the widest channel masks the spatializer
+     * is capable of rendering with individual channel positions.
+     * For instance a spatializer may only support virtual speaker positions for 5.1, it would
+     * therefore return {@link AudioFormat#CHANNEL_OUT_5POINT1}. But it would still return
+     * <code>true</code> when querying {@link #canBeSpatialized(AudioAttributes, AudioFormat)} it
+     * with a channel mask of {@link AudioFormat#CHANNEL_OUT_7POINT1POINT2}: the sound present
+     * in each channel would still be heard, but the sounds from the rear, side and top pairs would
+     * be mixed together, and be spatialized at the same location.
+     * @return a list of channel masks following the <code>CHANNEL_OUT_*</code> output channel
+     *     definitions found in {@link AudioFormat}.
+     */
+    @FlaggedApi(FLAG_SPATIALIZER_CAPABILITIES)
+    public @NonNull List<Integer> getSpatializedChannelMasks() {
+        try {
+            return mAm.getService().getSpatializedChannelMasks();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error querying getSpatializedChannelMasks", e);
+            return Collections.emptyList();
+        }
+    }
+
+    /**
      * Adds a listener to be notified of changes to the enabled state of the
      * {@code Spatializer}.
      * @param executor the {@code Executor} handling the callback
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index d8a8c8b..bbe8e4e 100644
--- a/media/java/android/media/flags/media_better_together.aconfig
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -141,6 +141,14 @@
 }
 
 flag {
+    name: "enable_route_visibility_control_api"
+    namespace: "media_better_together"
+    description: "API changes to allow more control over route visibility by route providers"
+    bug: "367799834"
+    is_exported: true
+}
+
+flag {
     name: "enable_screen_off_scanning"
     is_exported: true
     namespace: "media_solutions"
diff --git a/media/java/android/media/projection/IMediaProjection.aidl b/media/java/android/media/projection/IMediaProjection.aidl
index 8ee966d..dacd1bd 100644
--- a/media/java/android/media/projection/IMediaProjection.aidl
+++ b/media/java/android/media/projection/IMediaProjection.aidl
@@ -17,13 +17,14 @@
 package android.media.projection;
 
 import android.media.projection.IMediaProjectionCallback;
+import android.media.projection.StopReason;
 import android.os.IBinder;
 import android.app.ActivityOptions.LaunchCookie;
 
 /** {@hide} */
 interface IMediaProjection {
     void start(IMediaProjectionCallback callback);
-    void stop();
+    void stop(StopReason stopReason);
 
     boolean canProjectAudio();
     boolean canProjectVideo();
diff --git a/media/java/android/media/projection/IMediaProjectionManager.aidl b/media/java/android/media/projection/IMediaProjectionManager.aidl
index b104972..1d92eab 100644
--- a/media/java/android/media/projection/IMediaProjectionManager.aidl
+++ b/media/java/android/media/projection/IMediaProjectionManager.aidl
@@ -16,11 +16,13 @@
 
 package android.media.projection;
 
+import android.graphics.Rect;
 import android.media.projection.IMediaProjection;
 import android.media.projection.IMediaProjectionCallback;
 import android.media.projection.IMediaProjectionWatcherCallback;
 import android.media.projection.MediaProjectionInfo;
 import android.media.projection.ReviewGrantedConsentResult;
+import android.media.projection.StopReason;
 import android.os.IBinder;
 import android.view.ContentRecordingSession;
 
@@ -107,12 +109,7 @@
     @EnforcePermission("MANAGE_MEDIA_PROJECTION")
     @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
             + ".permission.MANAGE_MEDIA_PROJECTION)")
-    void stopActiveProjection();
-
-    @EnforcePermission("MANAGE_MEDIA_PROJECTION")
-    @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
-            + ".permission.MANAGE_MEDIA_PROJECTION)")
-    void notifyActiveProjectionCapturedContentResized(int width, int height);
+    void stopActiveProjection(in StopReason stopReason);
 
     @EnforcePermission("MANAGE_MEDIA_PROJECTION")
     @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
@@ -227,5 +224,11 @@
     @EnforcePermission("MANAGE_MEDIA_PROJECTION")
     @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
             + ".permission.MANAGE_MEDIA_PROJECTION)")
-    void notifyWindowingModeChanged(int contentToRecord, int targetProcessUid, int windowingMode);
+    oneway void notifyWindowingModeChanged(int contentToRecord, int targetProcessUid, int windowingMode);
+
+    @EnforcePermission("MANAGE_MEDIA_PROJECTION")
+    @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+            + ".permission.MANAGE_MEDIA_PROJECTION)")
+    oneway void notifyCaptureBoundsChanged(int contentToRecord, int targetProcessUid,
+            in Rect captureBounds);
 }
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 4114f53..f7f10df 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -317,7 +317,7 @@
     public void stop() {
         try {
             Log.d(TAG, "Content Recording: stopping projection");
-            mImpl.stop();
+            mImpl.stop(StopReason.STOP_HOST_APP);
         } catch (RemoteException e) {
             Log.e(TAG, "Unable to stop projection", e);
         }
diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java
index dc55e41..9cc2cca 100644
--- a/media/java/android/media/projection/MediaProjectionManager.java
+++ b/media/java/android/media/projection/MediaProjectionManager.java
@@ -297,10 +297,10 @@
      * Stop the current projection if there is one.
      * @hide
      */
-    public void stopActiveProjection() {
+    public void stopActiveProjection(@StopReason int stopReason) {
         try {
             Log.d(TAG, "Content Recording: stopping active projection");
-            mService.stopActiveProjection();
+            mService.stopActiveProjection(stopReason);
         } catch (RemoteException e) {
             Log.e(TAG, "Unable to stop the currently active media projection", e);
         }
diff --git a/media/java/android/media/projection/StopReason.aidl b/media/java/android/media/projection/StopReason.aidl
new file mode 100644
index 0000000..8611def
--- /dev/null
+++ b/media/java/android/media/projection/StopReason.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.media.projection;
+
+/**
+ * Identifies the reason for a MediaProjection being stopped (for metric logging purposes)
+ * @hide
+ */
+@Backing(type="int")
+enum StopReason {
+    STOP_UNKNOWN = 0,
+    STOP_HOST_APP = 1,
+    STOP_TARGET_REMOVED = 2,
+    STOP_DEVICE_LOCKED = 3,
+    STOP_PRIVACY_CHIP = 4,
+    STOP_QS_TILE = 5,
+    STOP_USER_SWITCH = 6,
+    STOP_FOREGROUND_SERVICE_CHANGE = 7,
+    STOP_NEW_PROJECTION = 8,
+    STOP_NEW_MEDIA_ROUTE = 9,
+    STOP_ERROR = 10,
+}
diff --git a/media/java/android/media/quality/IMediaQualityManager.aidl b/media/java/android/media/quality/IMediaQualityManager.aidl
index b7e75b7..dc3fbf6 100644
--- a/media/java/android/media/quality/IMediaQualityManager.aidl
+++ b/media/java/android/media/quality/IMediaQualityManager.aidl
@@ -30,42 +30,42 @@
  * @hide
  */
 interface IMediaQualityManager {
-    PictureProfile createPictureProfile(in PictureProfile pp);
-    void updatePictureProfile(in String id, in PictureProfile pp);
-    void removePictureProfile(in String id);
-    PictureProfile getPictureProfile(in int type, in String name);
-    List<PictureProfile> getPictureProfilesByPackage(in String packageName);
-    List<PictureProfile> getAvailablePictureProfiles();
-    List<String> getPictureProfilePackageNames();
-    List<String> getPictureProfileAllowList();
-    void setPictureProfileAllowList(in List<String> packages);
-    PictureProfileHandle getPictureProfileHandle(in String id);
+    PictureProfile createPictureProfile(in PictureProfile pp, int userId);
+    void updatePictureProfile(in String id, in PictureProfile pp, int userId);
+    void removePictureProfile(in String id, int userId);
+    PictureProfile getPictureProfile(in int type, in String name, int userId);
+    List<PictureProfile> getPictureProfilesByPackage(in String packageName, int userId);
+    List<PictureProfile> getAvailablePictureProfiles(int userId);
+    List<String> getPictureProfilePackageNames(int userId);
+    List<String> getPictureProfileAllowList(int userId);
+    void setPictureProfileAllowList(in List<String> packages, int userId);
+    PictureProfileHandle getPictureProfileHandle(in String id, int userId);
 
-    SoundProfile createSoundProfile(in SoundProfile pp);
-    void updateSoundProfile(in String id, in SoundProfile pp);
-    void removeSoundProfile(in String id);
-    SoundProfile getSoundProfile(in int type, in String name);
-    List<SoundProfile> getSoundProfilesByPackage(in String packageName);
-    List<SoundProfile> getAvailableSoundProfiles();
-    List<String> getSoundProfilePackageNames();
-    List<String> getSoundProfileAllowList();
-    void setSoundProfileAllowList(in List<String> packages);
+    SoundProfile createSoundProfile(in SoundProfile pp, int userId);
+    void updateSoundProfile(in String id, in SoundProfile pp, int userId);
+    void removeSoundProfile(in String id, int userId);
+    SoundProfile getSoundProfile(in int type, in String name, int userId);
+    List<SoundProfile> getSoundProfilesByPackage(in String packageName, int userId);
+    List<SoundProfile> getAvailableSoundProfiles(int userId);
+    List<String> getSoundProfilePackageNames(int userId);
+    List<String> getSoundProfileAllowList(int userId);
+    void setSoundProfileAllowList(in List<String> packages, int userId);
 
     void registerPictureProfileCallback(in IPictureProfileCallback cb);
     void registerSoundProfileCallback(in ISoundProfileCallback cb);
     void registerAmbientBacklightCallback(in IAmbientBacklightCallback cb);
 
-    List<ParamCapability> getParamCapabilities(in List<String> names);
+    List<ParamCapability> getParamCapabilities(in List<String> names, int userId);
 
-    boolean isSupported();
-    void setAutoPictureQualityEnabled(in boolean enabled);
-    boolean isAutoPictureQualityEnabled();
-    void setSuperResolutionEnabled(in boolean enabled);
-    boolean isSuperResolutionEnabled();
-    void setAutoSoundQualityEnabled(in boolean enabled);
-    boolean isAutoSoundQualityEnabled();
+    boolean isSupported(int userId);
+    void setAutoPictureQualityEnabled(in boolean enabled, int userId);
+    boolean isAutoPictureQualityEnabled(int userId);
+    void setSuperResolutionEnabled(in boolean enabled, int userId);
+    boolean isSuperResolutionEnabled(int userId);
+    void setAutoSoundQualityEnabled(in boolean enabled, int userId);
+    boolean isAutoSoundQualityEnabled(int userId);
 
-    void setAmbientBacklightSettings(in AmbientBacklightSettings settings);
-    void setAmbientBacklightEnabled(in boolean enabled);
-    boolean isAmbientBacklightEnabled();
+    void setAmbientBacklightSettings(in AmbientBacklightSettings settings, int userId);
+    void setAmbientBacklightEnabled(in boolean enabled, int userId);
+    boolean isAmbientBacklightEnabled(int userId);
 }
diff --git a/media/java/android/media/quality/MediaQualityContract.java b/media/java/android/media/quality/MediaQualityContract.java
index 3fac74b..7b0bd04 100644
--- a/media/java/android/media/quality/MediaQualityContract.java
+++ b/media/java/android/media/quality/MediaQualityContract.java
@@ -74,6 +74,130 @@
          */
         public static final String PARAMETER_SATURATION = "saturation";
 
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_COLOR = "color";
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_HUE = "hue";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_BACKLIGHT = "backlight";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_COLOR_TUNER_BRIGHTNESS = "color_tuner_brightness";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_COLOR_TUNER_SATURATION = "color_tuner_saturation";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_COLOR_TUNER_HUE = "color_tuner_hue";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_COLOR_TUNER_REDO_FFSET = "color_tuner_red_offset";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_COLOR_TUNER_GREEN_OFFSET = "color_tuner_green_offset";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_COLOR_TUNER_BLUE_OFFSET = "color_tuner_blue_offset";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_COLOR_TUNER_RED_GAIN = "color_tuner_red_gain";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_COLOR_TUNER_GREEN_GAIN = "color_tuner_green_gain";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_COLOR_TUNER_BLUE_GAIN = "color_tuner_blue_gain";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_AI_PQ = "ai_pq";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_AI_SUPER_RESOLUTION = "ai_super_resolution";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_NOISE_REDUCTION = "noise_reduction";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_MPEG_NOISE_REDUCTION = "mpeg_noise_reduction";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_FLESH_TONE = "flesh_tone";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_DECONTOUR = "decontour";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_DYNAMIC_LUMA_CONTROL = "dynamic_luma_control";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_FILM_MODE = "film_mode";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_BLACK_STRETCH = "black_stretch";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_BLUE_STRETCH = "blue_stretch";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_COLOR_TUNE = "color_tune";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_COLOR_TEMPERATURE = "color_temperature";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_GLOBAL_DIMMING = "global_dimming";
+
         private PictureQuality() {
         }
     }
@@ -105,6 +229,129 @@
          */
         public static final String PARAMETER_TREBLE = "treble";
 
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_SOUND_MODE = "sound_mode";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_SURROUND_SOUND = "surround_sound";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_EQUALIZER_DETAIL = "equalizer_detail";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_SPEAKERS = "speakers";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_SPEAKERS_DELAY = "speakers_delay";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_EARC = "earc";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_AUTO_VOLUME_CONTROL = "auto_volume_control";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_DOWN_MIX_MODE = "down_mix_mode";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_DTS_DRC = "dts_drc";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_DOLBY_AUDIO_PROCESSING = "dolby_audio_processing";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_DOLBY_AUDIO_PROCESSING_SOUND_MODE =
+                "dolby_audio_processing_sound_mode";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_DOLBY_AUDIO_PROCESSING_VOLUME_LEVELER =
+                "dolby_audio_processing_volume_leveler";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_DOLBY_AUDIO_PROCESSING_SURROUND_VIRTUALIZER =
+                "dolby_audio_processing_surround_virtualizer";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_DOLBY_AUDIO_PROCESSING_DOLBY_ATMOS =
+                "dolby_audio_processing_dolby_atmos";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_DIALOGUE_ENHANCER = "dialogue_enhancer";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_DTS_VIRTUAL_X = "dts_virtual_x";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_DTS_VIRTUAL_X_TBHDX = "dts_virtual_x_tbhdx";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_DTS_VIRTUAL_X_LIMITER = "dts_virtual_x_limiter";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_DTS_VIRTUAL_X_TRU_SURROUND_X =
+                "dts_virtual_x_tru_surround_x";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_DTS_VIRTUAL_X_TRU_VOLUME_HD =
+                "dts_virtual_x_tru_volume_hd";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_DTS_VIRTUAL_X_DIALOG_CLARITY =
+                "dts_virtual_x_dialog_clarity";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_DTS_VIRTUAL_X_DEFINITION = "dts_virtual_x_definition";
+
+        /**
+         * @hide
+         */
+        public static final String PARAMETER_DTS_VIRTUAL_X_HEIGHT = "dts_virtual_x_height";
+
+
         private SoundQuality() {
         }
     }
diff --git a/media/java/android/media/quality/MediaQualityManager.java b/media/java/android/media/quality/MediaQualityManager.java
index 5005597..d4de99a 100644
--- a/media/java/android/media/quality/MediaQualityManager.java
+++ b/media/java/android/media/quality/MediaQualityManager.java
@@ -47,6 +47,7 @@
 
     private final IMediaQualityManager mService;
     private final Context mContext;
+    private final int mUserId;
     private final Object mLock = new Object();
     // @GuardedBy("mLock")
     private final List<PictureProfileCallbackRecord> mPpCallbackRecords = new ArrayList<>();
@@ -61,6 +62,7 @@
      */
     public MediaQualityManager(Context context, IMediaQualityManager service) {
         mContext = context;
+        mUserId = context.getUserId();
         mService = service;
         IPictureProfileCallback ppCallback = new IPictureProfileCallback.Stub() {
             @Override
@@ -219,7 +221,7 @@
     public PictureProfile getPictureProfile(
             @PictureProfile.ProfileType int type, @NonNull String name) {
         try {
-            return mService.getPictureProfile(type, name);
+            return mService.getPictureProfile(type, name, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -236,7 +238,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
     public List<PictureProfile> getPictureProfilesByPackage(@NonNull String packageName) {
         try {
-            return mService.getPictureProfilesByPackage(packageName);
+            return mService.getPictureProfilesByPackage(packageName, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -248,7 +250,7 @@
     @NonNull
     public List<PictureProfile> getAvailablePictureProfiles() {
         try {
-            return mService.getAvailablePictureProfiles();
+            return mService.getAvailablePictureProfiles(mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -265,7 +267,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
     public List<String> getPictureProfilePackageNames() {
         try {
-            return mService.getPictureProfilePackageNames();
+            return mService.getPictureProfilePackageNames(mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -277,7 +279,7 @@
      */
     public PictureProfileHandle getPictureProfileHandle(String id) {
         try {
-            return mService.getPictureProfileHandle(id);
+            return mService.getPictureProfileHandle(id, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -291,7 +293,7 @@
      */
     public void createPictureProfile(@NonNull PictureProfile pp) {
         try {
-            mService.createPictureProfile(pp);
+            mService.createPictureProfile(pp, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -303,7 +305,7 @@
      */
     public void updatePictureProfile(@NonNull String profileId, @NonNull PictureProfile pp) {
         try {
-            mService.updatePictureProfile(profileId, pp);
+            mService.updatePictureProfile(profileId, pp, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -315,7 +317,7 @@
      */
     public void removePictureProfile(@NonNull String profileId) {
         try {
-            mService.removePictureProfile(profileId);
+            mService.removePictureProfile(profileId, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -362,7 +364,7 @@
     public SoundProfile getSoundProfile(
             @SoundProfile.ProfileType int type, @NonNull String name) {
         try {
-            return mService.getSoundProfile(type, name);
+            return mService.getSoundProfile(type, name, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -379,7 +381,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
     public List<SoundProfile> getSoundProfilesByPackage(@NonNull String packageName) {
         try {
-            return mService.getSoundProfilesByPackage(packageName);
+            return mService.getSoundProfilesByPackage(packageName, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -391,7 +393,7 @@
     @NonNull
     public List<SoundProfile> getAvailableSoundProfiles() {
         try {
-            return mService.getAvailableSoundProfiles();
+            return mService.getAvailableSoundProfiles(mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -409,7 +411,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
     public List<String> getSoundProfilePackageNames() {
         try {
-            return mService.getSoundProfilePackageNames();
+            return mService.getSoundProfilePackageNames(mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -424,7 +426,7 @@
      */
     public void createSoundProfile(@NonNull SoundProfile sp) {
         try {
-            mService.createSoundProfile(sp);
+            mService.createSoundProfile(sp, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -436,7 +438,7 @@
      */
     public void updateSoundProfile(@NonNull String profileId, @NonNull SoundProfile sp) {
         try {
-            mService.updateSoundProfile(profileId, sp);
+            mService.updateSoundProfile(profileId, sp, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -448,7 +450,7 @@
      */
     public void removeSoundProfile(@NonNull String profileId) {
         try {
-            mService.removeSoundProfile(profileId);
+            mService.removeSoundProfile(profileId, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -460,7 +462,7 @@
     @NonNull
     public List<ParamCapability> getParamCapabilities(@NonNull List<String> names) {
         try {
-            return mService.getParamCapabilities(names);
+            return mService.getParamCapabilities(names, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -478,7 +480,7 @@
     @NonNull
     public List<String> getPictureProfileAllowList() {
         try {
-            return mService.getPictureProfileAllowList();
+            return mService.getPictureProfileAllowList(mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -492,7 +494,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
     public void setPictureProfileAllowList(@NonNull List<String> packageNames) {
         try {
-            mService.setPictureProfileAllowList(packageNames);
+            mService.setPictureProfileAllowList(packageNames, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -510,7 +512,7 @@
     @NonNull
     public List<String> getSoundProfileAllowList() {
         try {
-            return mService.getSoundProfileAllowList();
+            return mService.getSoundProfileAllowList(mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -524,7 +526,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
     public void setSoundProfileAllowList(@NonNull List<String> packageNames) {
         try {
-            mService.setSoundProfileAllowList(packageNames);
+            mService.setSoundProfileAllowList(packageNames, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -536,7 +538,7 @@
      */
     public boolean isSupported() {
         try {
-            return mService.isSupported();
+            return mService.isSupported(mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -554,7 +556,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
     public void setAutoPictureQualityEnabled(boolean enabled) {
         try {
-            mService.setAutoPictureQualityEnabled(enabled);
+            mService.setAutoPictureQualityEnabled(enabled, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -565,7 +567,7 @@
      */
     public boolean isAutoPictureQualityEnabled() {
         try {
-            return mService.isAutoPictureQualityEnabled();
+            return mService.isAutoPictureQualityEnabled(mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -582,7 +584,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
     public void setSuperResolutionEnabled(boolean enabled) {
         try {
-            mService.setSuperResolutionEnabled(enabled);
+            mService.setSuperResolutionEnabled(enabled, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -593,7 +595,7 @@
      */
     public boolean isSuperResolutionEnabled() {
         try {
-            return mService.isSuperResolutionEnabled();
+            return mService.isSuperResolutionEnabled(mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -611,7 +613,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
     public void setAutoSoundQualityEnabled(boolean enabled) {
         try {
-            mService.setAutoSoundQualityEnabled(enabled);
+            mService.setAutoSoundQualityEnabled(enabled, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -622,7 +624,7 @@
      */
     public boolean isAutoSoundQualityEnabled() {
         try {
-            return mService.isAutoSoundQualityEnabled();
+            return mService.isAutoSoundQualityEnabled(mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -668,7 +670,7 @@
             @NonNull AmbientBacklightSettings settings) {
         Preconditions.checkNotNull(settings);
         try {
-            mService.setAmbientBacklightSettings(settings);
+            mService.setAmbientBacklightSettings(settings, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -679,7 +681,7 @@
      */
     public boolean isAmbientBacklightEnabled() {
         try {
-            return mService.isAmbientBacklightEnabled();
+            return mService.isAmbientBacklightEnabled(mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -692,7 +694,7 @@
      */
     public void setAmbientBacklightEnabled(boolean enabled) {
         try {
-            mService.setAmbientBacklightEnabled(enabled);
+            mService.setAmbientBacklightEnabled(enabled, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/analog/IAnalogAttributeInterface.aidl
similarity index 73%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/analog/IAnalogAttributeInterface.aidl
index 7d3d8b9..550acba 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/analog/IAnalogAttributeInterface.aidl
@@ -13,10 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.analog;
+
+/**
+ * @hide
+ */
+interface IAnalogAttributeInterface {
+    int getVersion();
+    void setColorSystemCapability(in String[] list);
+    String[] getColorSystemCapability();
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/cam/ICamAppInfoListener.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/cam/ICamAppInfoListener.aidl
index 7d3d8b9..73ae209 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/cam/ICamAppInfoListener.aidl
@@ -13,10 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.cam;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ICamAppInfoListener {
+    void onCamAppInfoChanged(int slotId, in Bundle appInfo);
 }
diff --git a/media/java/android/media/tv/extension/cam/ICamAppInfoService.aidl b/media/java/android/media/tv/extension/cam/ICamAppInfoService.aidl
new file mode 100644
index 0000000..d3a03bc
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamAppInfoService.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.media.tv.extension.cam;
+
+import android.media.tv.extension.cam.ICamAppInfoListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface ICamAppInfoService {
+    // Register ICamAppInfoListener to get CICAM Application Information updates.
+    void addCamAppInfoListener(ICamAppInfoListener listener);
+    // Unregister ICamAppInfoListener and stop get Application Information notify.
+    void removeCamAppInfoListener(ICamAppInfoListener listener);
+    // Get the Application Information of the CICAM.
+    int getCamAppInfo(int slotId, out Bundle appInfo);
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/cam/ICamDrmInfoListener.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/cam/ICamDrmInfoListener.aidl
index 7d3d8b9..c727837 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/cam/ICamDrmInfoListener.aidl
@@ -13,10 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.cam;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ICamDrmInfoListener {
+    void onCamDrmInfoChanged(int slotId, in Bundle camDrmInfo);
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/cam/ICamHostControlAskReleaseReplyCallback.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/cam/ICamHostControlAskReleaseReplyCallback.aidl
index 7d3d8b9..83f2c01 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/cam/ICamHostControlAskReleaseReplyCallback.aidl
@@ -13,10 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.cam;
+
+/**
+ * @hide
+ */
+oneway interface ICamHostControlAskReleaseReplyCallback {
+    void onAskReleaseReply(String sessionToken, int replyStatus);
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/cam/ICamHostControlInfoListener.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/cam/ICamHostControlInfoListener.aidl
index 7d3d8b9..f48ca57 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/cam/ICamHostControlInfoListener.aidl
@@ -13,10 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.cam;
+
+/**
+ * @hide
+ */
+oneway interface ICamHostControlInfoListener {
+    void onCamHostControlInfoChanged(String sessionToken, int sessionStatus);
 }
diff --git a/media/java/android/media/tv/extension/cam/ICamHostControlService.aidl b/media/java/android/media/tv/extension/cam/ICamHostControlService.aidl
new file mode 100644
index 0000000..6f6c376
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamHostControlService.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.media.tv.extension.cam;
+
+import android.media.tv.extension.cam.ICamHostControlAskReleaseReplyCallback;
+import android.media.tv.extension.cam.ICamHostControlInfoListener;
+
+/**
+ * @hide
+ */
+interface ICamHostControlService {
+    // Register the listener to monitor host control session updates.
+    void addCamHostcontrolInfoListener(ICamHostControlInfoListener listener);
+    // Unregister ICamHostControlInfoListener and stop monitoring.
+    void removeCamHostcontrolInfoListener(ICamHostControlInfoListener listener);
+    // Request CICAM to release the resource.
+    int sendCamHostControlAskRelease(String sessionToken,
+        ICamHostControlAskReleaseReplyCallback callback);
+    // Enable/disable the host control mode.
+    void setHostControlMode(String sessionToken, boolean enable);
+}
diff --git a/media/java/android/media/tv/extension/cam/ICamHostControlTuneQuietlyFlag.aidl b/media/java/android/media/tv/extension/cam/ICamHostControlTuneQuietlyFlag.aidl
new file mode 100644
index 0000000..25a78b9
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamHostControlTuneQuietlyFlag.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.media.tv.extension.cam;
+
+import android.media.tv.extension.cam.ICamHostControlTuneQuietlyFlagListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface ICamHostControlTuneQuietlyFlag {
+    // Register listener to notify host control tune_quietly_flag.
+    void addHcTuneQuietlyFlagListener(ICamHostControlTuneQuietlyFlagListener listener);
+    // Remove listener and stop monitor host control tune_quietly_flag.
+    void removeHcTuneQuietlyFlagListener(ICamHostControlTuneQuietlyFlagListener listener);
+    // Returns host control tune_quietly_flag value.
+    Bundle getHcTuneQuietlyFlag(String sessionToken);
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/cam/ICamHostControlTuneQuietlyFlagListener.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/cam/ICamHostControlTuneQuietlyFlagListener.aidl
index 7d3d8b9..5967124 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/cam/ICamHostControlTuneQuietlyFlagListener.aidl
@@ -13,10 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.cam;
+
+/**
+ * @hide
+ */
+oneway interface ICamHostControlTuneQuietlyFlagListener {
+    void onHcTuneQuietlyFlagChanged(String sessionToken, int tuneQuietlyFlag);
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/cam/ICamInfoListener.aidl
similarity index 65%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/cam/ICamInfoListener.aidl
index 7d3d8b9..5410bff 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/cam/ICamInfoListener.aidl
@@ -13,10 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.cam;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ICamInfoListener {
+    void onCamInfoChanged(int slotId, in Bundle updatedCamInfo);
+    void onSlotInfoChanged(int slotId, in Bundle updatedSlotInfo);
+    void onNewTypeCamInsert(int slotId, in Bundle newCamType);
 }
diff --git a/media/java/android/media/tv/extension/cam/ICamMonitoringService.aidl b/media/java/android/media/tv/extension/cam/ICamMonitoringService.aidl
new file mode 100644
index 0000000..7b8014c
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamMonitoringService.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.media.tv.extension.cam;
+
+import android.media.tv.extension.cam.ICamInfoListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface ICamMonitoringService {
+    // Register a listener for slot/CAM info updates.
+    void addCamInfoListener(in ICamInfoListener listener);
+    // Unregister a listener for slot/CAM info updates.
+    void removeCamInfoListener(in ICamInfoListener listener);
+    // Get CAM information for the specified slot.
+    Bundle getCamInfo(int slotId);
+    // Get slot information.
+    Bundle getSlotInfo(int slotId);
+    // Returns list of slot Ids.
+    int[] getSlotIds();
+    // Check if the country supports CAM.
+    boolean isCamSupported();
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/cam/ICamPinCapabilityListener.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/cam/ICamPinCapabilityListener.aidl
index 7d3d8b9..f92304a 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/cam/ICamPinCapabilityListener.aidl
@@ -13,10 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.cam;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ICamPinCapabilityListener {
+    void onCamPinCapabilityChanged(int slotId, in Bundle bundle);
 }
diff --git a/media/java/android/media/tv/extension/cam/ICamPinService.aidl b/media/java/android/media/tv/extension/cam/ICamPinService.aidl
new file mode 100644
index 0000000..3f6cb28
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/ICamPinService.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.media.tv.extension.cam;
+
+import android.media.tv.extension.cam.ICamPinCapabilityListener;
+import android.media.tv.extension.cam.ICamPinStatusListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface ICamPinService {
+    // Register ICamPinCapabilityListener to get CICAM updates.
+    void addCamPinCapabilityListener(in ICamPinCapabilityListener listener);
+    // Unregister ICamPinCapabilityListener and stop monitor PIN status and PIN capability.
+    void removeCamPinCapabilityListener(in ICamPinCapabilityListener listener);
+    // Send the PinCode that needs to be validated by CICAM.
+    int requestCamPinValidation(int slotId, in int[] pinCode, in ICamPinStatusListener listener);
+    // Get the PIN capabilities of the CICAM.
+    int getCamPinCapability(int slotId, out Bundle camPinCapability);
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/cam/ICamPinStatusListener.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/cam/ICamPinStatusListener.aidl
index 7d3d8b9..efbc394 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/cam/ICamPinStatusListener.aidl
@@ -13,10 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.cam;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ICamPinStatusListener {
+    void onCamPinValidationReply(int slotId, in Bundle bundle);
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/cam/ICamProfileInterface.aidl
similarity index 62%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/cam/ICamProfileInterface.aidl
index 7d3d8b9..3f1d40c 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/cam/ICamProfileInterface.aidl
@@ -13,10 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.cam;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface ICamProfileInterface {
+    // Get CAM service update information for special slot.
+    Bundle getCamServiceUpdateInfo(int slotNumber);
+    // Request CAM TIS resend cam info update broadcast message when APK boot up.
+    void requestResendProfileInfoBroadcastACON();
 }
diff --git a/media/java/android/media/tv/extension/cam/IContentControlService.aidl b/media/java/android/media/tv/extension/cam/IContentControlService.aidl
new file mode 100644
index 0000000..6db79ab
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/IContentControlService.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.media.tv.extension.cam;
+
+import android.media.tv.extension.cam.ICamDrmInfoListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IContentControlService {
+    // Register the listener to notify the DRM info changed by the CICAM.
+    void addCamDrmInfoListener(in ICamDrmInfoListener listener);
+    // Unregister listener to stop monitor DRM Info.
+    void removeCamDrmInfoListener(in ICamDrmInfoListener listener);
+    // Get the DRM Info of current watching channel.
+    int getCamDrmInfo(int slotId, out Bundle camDrmInfo);
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/cam/IEnterMenuErrorCallback.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/cam/IEnterMenuErrorCallback.aidl
index 7d3d8b9..ff61ddc 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/cam/IEnterMenuErrorCallback.aidl
@@ -13,10 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.cam;
+
+/**
+ * @hide
+ */
+oneway interface IEnterMenuErrorCallback {
+    void onAppInfoEnterMenuError();
 }
diff --git a/media/java/android/media/tv/extension/cam/IMmiInterface.aidl b/media/java/android/media/tv/extension/cam/IMmiInterface.aidl
new file mode 100644
index 0000000..17a2a9c
--- /dev/null
+++ b/media/java/android/media/tv/extension/cam/IMmiInterface.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.media.tv.extension.cam;
+
+import android.media.tv.extension.cam.IEnterMenuErrorCallback;
+import android.media.tv.extension.cam.IMmiSession;
+import android.media.tv.extension.cam.IMmiStatusCallback;
+
+
+/**
+ * @hide
+ */
+interface IMmiInterface {
+    // Open a session for MMI.
+    IMmiSession openSession(int slotId, IMmiStatusCallback callback);
+    // Request to display CI Module setup screen.
+    void appInfoEnterMenu(int slotId, IEnterMenuErrorCallback callback);
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/cam/IMmiSession.aidl
similarity index 60%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/cam/IMmiSession.aidl
index 7d3d8b9..c4f2762 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/cam/IMmiSession.aidl
@@ -13,10 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.cam;
+
+/**
+ * @hide
+ */
+interface IMmiSession {
+    // Send user answers to CAM on the MMI Menu screen.
+    void setMenuListAnswer(int response);
+    // Send user answers to CAM on the MMI Enq screen.
+    void setEnquiryAnswer(int answerId, String answer);
+    // Send CloseMmi APDU to Cam.
+    void closeMmi();
+    // Release MMI session.
+    void close();
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/cam/IMmiStatusCallback.aidl
similarity index 72%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/cam/IMmiStatusCallback.aidl
index 7d3d8b9..3e68ced 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/cam/IMmiStatusCallback.aidl
@@ -13,10 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.cam;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IMmiStatusCallback {
+    void onMmiEnq(in Bundle request);
+    void onMmiListMenu(in Bundle request);
+    void onMmiClose();
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/clienttoken/IClientToken.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/clienttoken/IClientToken.aidl
index 7d3d8b9..fa701b3 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/clienttoken/IClientToken.aidl
@@ -13,10 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.clienttoken;
+
+/**
+ * @hide
+ */
+interface IClientToken {
+    String generateClientToken();
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/event/IEventDownload.aidl
similarity index 61%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/event/IEventDownload.aidl
index 7d3d8b9..29c7553 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/event/IEventDownload.aidl
@@ -13,10 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.event;
+
+import android.media.tv.extension.event.IEventDownloadListener;
+import android.os.Bundle;
+import android.os.IBinder;
+
+/**
+ * @hide
+ */
+interface IEventDownload {
+    // Create an event download session and return it as a Ibinder for DVB/DTMB
+    IBinder createSession(in Bundle eventDownloadParams, in IEventDownloadListener listener);
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/event/IEventDownloadListener.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/event/IEventDownloadListener.aidl
index 7d3d8b9..6d7d61f 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/event/IEventDownloadListener.aidl
@@ -13,10 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.event;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IEventDownloadListener {
+    void onCompleted(in Bundle status);
 }
diff --git a/media/java/android/media/tv/extension/event/IEventDownloadSession.aidl b/media/java/android/media/tv/extension/event/IEventDownloadSession.aidl
new file mode 100644
index 0000000..fe7ee37
--- /dev/null
+++ b/media/java/android/media/tv/extension/event/IEventDownloadSession.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.media.tv.extension.event;
+
+import android.net.Uri;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IEventDownloadSession {
+    // Determine to execute barker channel or silent tune flow for related service type
+    int isBarkerOrSequentialDownloadByServiceType(in Bundle eventDownloadParams);
+    // Determine whether to start barker channel or silent tune flow.
+    int isBarkerOrSequentialDownloadByServiceRecord(in Bundle eventDownloadParams);
+    // Start event download.
+    void startTuningMultiplex(in Uri channelUri);
+    // Set active window channels.
+    void setActiveWindowChannelInfo(in Uri[] activeWinChannelInfos);
+    // Cancel barker channel or silent tune flow.
+    void cancel();
+    // Release barker channel or silent tune flow.
+    void release();
+}
diff --git a/media/java/android/media/tv/extension/event/IEventMonitor.aidl b/media/java/android/media/tv/extension/event/IEventMonitor.aidl
new file mode 100644
index 0000000..f6e7bd1
--- /dev/null
+++ b/media/java/android/media/tv/extension/event/IEventMonitor.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.media.tv.extension.event;
+
+import android.media.tv.extension.event.IEventMonitorListener;
+import android.net.Uri;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IEventMonitor {
+    // Get present event information.
+    Bundle getPresentEventInfo(long channelDbId);
+    // Add present event information listener.
+    void addPresentEventInfoListener(in IEventMonitorListener listener);
+    // Remove present event information listener.
+    void removePresentEventInfoListener(in IEventMonitorListener listener);
+    // Get following event information.
+    Bundle getFollowingEventInfo(long channelDbId);
+    // Add following event information listener.
+    void addFollowingEventInfoListener(in IEventMonitorListener listener);
+    // Remove following event information listener.
+    void removeFollowingEventInfoListener(in IEventMonitorListener listener);
+    // Get SDT guidance information.
+    Bundle getSdtGuidanceInfo(long channelDbId);
+    // Set Event Background channel list info.
+    void setBgmTuneChannelInfo(in Uri[] tuneChannelInfos);
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/event/IEventMonitorListener.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/event/IEventMonitorListener.aidl
index 7d3d8b9..a00e542 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/event/IEventMonitorListener.aidl
@@ -13,10 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.event;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IEventMonitorListener {
+    void onInfoChanged(long channelDbId, in Bundle eventinfo);
 }
diff --git a/media/java/android/media/tv/extension/scan/IFavoriteNetwork.aidl b/media/java/android/media/tv/extension/scan/IFavoriteNetwork.aidl
new file mode 100644
index 0000000..ff78aa4
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IFavoriteNetwork.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.media.tv.extension.scan;
+
+import android.media.tv.extension.scan.IFavoriteNetworkListener;
+import android.os.Bundle;
+
+/**
+ * Country: Norway
+ * Broadcast Type: BROADCAST_TYPE_DVB_T
+ * (Operator: RiksTV)
+ *
+ * @hide
+ */
+interface IFavoriteNetwork {
+    // Get the favorite network information,If there are no conflicts, the array of Bundle is empty.
+    Bundle[] getFavoriteNetworks();
+    // Select and set one of two or more favorite networks detected by the service scan.
+    int setFavoriteNetwork(in Bundle favoriteNetworkSettings);
+    // Set the listener to be invoked when two or more favorite networks are detected.
+    int setListener(in IFavoriteNetworkListener listener);
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/scan/IFavoriteNetworkListener.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/scan/IFavoriteNetworkListener.aidl
index 7d3d8b9..6994224 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/scan/IFavoriteNetworkListener.aidl
@@ -13,10 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.scan;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IFavoriteNetworkListener {
+    void onDetectFavoriteNetwork(in Bundle detectFavoriteNetworks);
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/scan/IHDPlusInfo.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/scan/IHDPlusInfo.aidl
index 7d3d8b9..cdf6e23 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/scan/IHDPlusInfo.aidl
@@ -13,10 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.scan;
+
+/**
+ * @hide
+ */
+interface IHDPlusInfo {
+    // Specifying a HDPlusInfo and start a network scan.
+    int setHDPlusInfo(String isBlindScanContinue, String isHDMode);
 }
diff --git a/media/java/android/media/tv/extension/scan/ILcnConflict.aidl b/media/java/android/media/tv/extension/scan/ILcnConflict.aidl
new file mode 100644
index 0000000..5dff39e
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ILcnConflict.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.media.tv.extension.scan;
+
+import android.media.tv.extension.scan.ILcnConflictListener;
+import android.os.Bundle;
+
+/**
+ * Country: Italy, France
+ * Broadcast Type: BROADCAST_TYPE_DVB_T
+ *
+ * @hide
+ */
+interface ILcnConflict {
+    // Get the LCN conflict groups information, If there are no conflicts, the array of Bundle is empty.
+    Bundle[] getLcnConflictGroups();
+    // Resolve LCN conflicts caused by service scans.
+    int resolveLcnConflict(in Bundle[] lcnConflictSettings);
+    // Set the listener to be invoked the LCN conflict event.
+    int setListener(in ILcnConflictListener listener);
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/scan/ILcnConflictListener.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/scan/ILcnConflictListener.aidl
index 7d3d8b9..6bbbeb8 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/scan/ILcnConflictListener.aidl
@@ -13,10 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.scan;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ILcnConflictListener {
+    void onDetectLcnConflict(in Bundle detectLcnConflicts);
 }
diff --git a/media/java/android/media/tv/extension/scan/ILcnV2ChannelList.aidl b/media/java/android/media/tv/extension/scan/ILcnV2ChannelList.aidl
new file mode 100644
index 0000000..f9a9d34
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ILcnV2ChannelList.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.media.tv.extension.scan;
+
+import android.media.tv.extension.scan.ILcnV2ChannelListListener;
+import android.os.Bundle;
+
+/**
+ * Country: (NorDig etc.)
+ * Broadcast Type: BROADCAST_TYPE_DVB_T, BROADCAST_TYPE_DVB_C
+ *
+ * @hide
+ */
+interface ILcnV2ChannelList {
+    // Get the LCN V2 channel list information. If there are no conflicts, the array of Bundle is empty.
+    Bundle[] getLcnV2ChannelLists();
+    // Select and set one of two or more LCN V2 channel list detected by the service scan.
+    int setLcnV2ChannelList(in Bundle lcnV2ChannelListSettings);
+    // Set the listener to be invoked when two or more LCN V2 channel list are detected.
+    int setListener(in ILcnV2ChannelListListener listener);
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/scan/ILcnV2ChannelListListener.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/scan/ILcnV2ChannelListListener.aidl
index 7d3d8b9..cbdb83c 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/scan/ILcnV2ChannelListListener.aidl
@@ -13,10 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.scan;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ILcnV2ChannelListListener {
+    void onDetectLcnV2ChannelList(in Bundle detectLcnV2ChannelList);
 }
diff --git a/media/java/android/media/tv/extension/scan/IOperatorDetection.aidl b/media/java/android/media/tv/extension/scan/IOperatorDetection.aidl
new file mode 100644
index 0000000..770f866
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IOperatorDetection.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.media.tv.extension.scan;
+
+import android.media.tv.extension.scan.IOperatorDetectionListener;
+import android.os.Bundle;
+
+/**
+ * Country: Any
+ * Broadcast Type: BROADCAST_TYPE_DVB_S
+ * (Operator: M7)
+ *
+ * @hide
+ */
+interface IOperatorDetection {
+    // Set the operator selected info for scanning.
+    int setOperatorDetection(in Bundle operatorSelected);
+    // Set the listener to be invoked when one or more operator detection has been detected by
+    // operator detection searches.
+    int setListener(in IOperatorDetectionListener listener);
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/scan/IOperatorDetectionListener.aidl
similarity index 73%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/scan/IOperatorDetectionListener.aidl
index 7d3d8b9..7dcd461 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/scan/IOperatorDetectionListener.aidl
@@ -13,10 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.scan;
+
+import android.os.Bundle;
+
+
+/**
+ * @hide
+ */
+oneway interface IOperatorDetectionListener {
+    void onDetectOperatorDetectionList(in Bundle[] detectOperatorDetectionList);
 }
diff --git a/media/java/android/media/tv/extension/scan/IRegionChannelList.aidl b/media/java/android/media/tv/extension/scan/IRegionChannelList.aidl
new file mode 100644
index 0000000..fe755f8
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IRegionChannelList.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.media.tv.extension.scan;
+
+import android.media.tv.extension.scan.IRegionChannelListListener;
+
+/**
+ * @hide
+ */
+interface IRegionChannelList {
+    // Set the region channel list for scanning.
+    int setRegionChannelList(String regionChannelList);
+    // Set the listener to be invoked when one or more region channel list has been detected by
+    // region channel list searches.
+    int setListener(in IRegionChannelListListener listener);
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/scan/IRegionChannelListListener.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/scan/IRegionChannelListListener.aidl
index 7d3d8b9..06b0eb5 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/scan/IRegionChannelListListener.aidl
@@ -13,10 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.scan;
+
+/**
+ * @hide
+ */
+oneway interface IRegionChannelListListener {
+    void onDetectRegionChannelList(in String[] detectRegionChannelList);
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/scan/IScanInterface.aidl
similarity index 60%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/scan/IScanInterface.aidl
index 7d3d8b9..b44d1d2 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/scan/IScanInterface.aidl
@@ -13,10 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.scan;
+
+import android.media.tv.extension.scan.IScanListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IScanInterface {
+    IBinder createSession(int broadcastType, String countryCode, String operator,
+        in IScanListener listener);
+    Bundle getParameters(int broadcastType, String countryCode, String operator,
+        in Bundle params);
 }
diff --git a/media/java/android/media/tv/extension/scan/IScanListener.aidl b/media/java/android/media/tv/extension/scan/IScanListener.aidl
new file mode 100644
index 0000000..2c4807f
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IScanListener.aidl
@@ -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 android.media.tv.extension.scan;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IScanListener {
+    // notify events during scan.
+    void onEvent(in Bundle eventArgs);
+    // notify the scan progress.
+    void onScanProgress(String scanProgress, in Bundle scanProgressInfo);
+    // notify the scan completion.
+    void onScanCompleted(int scanResult);
+    // notify that the temporaily held channel list is stored.
+    void onStoreCompleted(int storeResult);
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/scan/IScanSatSearch.aidl
similarity index 71%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/scan/IScanSatSearch.aidl
index 7d3d8b9..b8074fc 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/scan/IScanSatSearch.aidl
@@ -13,10 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.scan;
+
+/**
+ * For satellite search function.
+ * @hide
+ */
+interface IScanSatSearch {
+    // Set currecnt LNB as customized LNB, default LNB is universal LNB
+    int setCustomizedLnb(String customizedLnb);
 }
diff --git a/media/java/android/media/tv/extension/scan/IScanSession.aidl b/media/java/android/media/tv/extension/scan/IScanSession.aidl
new file mode 100644
index 0000000..d42eca1
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IScanSession.aidl
@@ -0,0 +1,75 @@
+/*
+ * 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.media.tv.extension.scan;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IScanSession {
+    // Start a service scan.
+    int startScan(int broadcastType, String countryCode, String operator, in int[] frequency,
+        String scanType, String languageCode);
+    // Reset the scan information held in TIS.
+    int resetScan();
+    // Cancel scan.
+    int cancelScan();
+
+    // Get available interface for created ScanExtension interface.
+    String[] getAvailableExtensionInterfaceNames();
+    // Get extension interface for Scan.
+    IBinder getExtensionInterface(String name);
+
+    // Clear the results of the service scan from the service database.
+    int clearServiceList(in Bundle optionalClearParams);
+    // Store the results of the service scan from the service database.
+    int storeServiceList();
+    // Get a service information specified by the service information ID.
+    Bundle getServiceInfo(String serviceInfoId, in String[] keys);
+    // Get a service information ID list.
+    String[] getServiceInfoIdList();
+    // Get a list of service info by the filter.
+    Bundle getServiceInfoList(in Bundle filterInfo, in String[] keys);
+    // Update the service information.
+    int updateServiceInfo(in Bundle serviceInfo);
+    // Updates the service information for the specified service information ID in array list.
+    int updateServiceInfoByList(in Bundle[] serviceInfo);
+
+    /* DVBI specific functions */
+    // Get all of the serviceLists, parsed from Local TV storage, Broadcast, USB file discovery.
+    Bundle getServiceLists();
+    // Users choose one serviceList from the serviceLists, and install the services.
+    int setServiceList(int serviceListRecId);
+    // Get all of the packageData, parsed from the selected serviceList XML.
+    Bundle getPackageData();
+    // Choose the package using package id and install the corresponding services.
+    int setPackage(String packageId);
+    // Get all of the countryRegionData, parsed from the selected serviceList XML.
+    Bundle getCountryRegionData();
+    // Choose the countryRegion using countryRegion id, and install the corresponding services.
+    int setCountryRegion(String regionId);
+    // Get all of the regionData, parsed from the selected serviceList XML.
+    Bundle getRegionData();
+    // Choose the region using the regionData id, and install the corresponding services.
+    int setRegion(String regionId);
+
+    // Get unique session token for the scan.
+    String getSessionToken();
+    // Release scan resource, the register listener will be released.
+    int release();
+}
diff --git a/media/java/android/media/tv/extension/scan/ITargetRegion.aidl b/media/java/android/media/tv/extension/scan/ITargetRegion.aidl
new file mode 100644
index 0000000..417e122
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ITargetRegion.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.media.tv.extension.scan;
+
+import android.media.tv.extension.scan.ITargetRegionListener;
+
+import android.os.Bundle;
+
+/**
+ * Country: U.K.
+ * Broadcast Type: BROADCAST_TYPE_DVB_T
+ *
+ * @hide
+ */
+interface ITargetRegion {
+    // Get the target regions information. If there are no conflicts, the array of Bundle is empty.
+    Bundle[] getTargetRegions();
+    // Select and set one of two or more target region detected by the service scan.
+    int setTargetRegion(in Bundle targetRegionSettings);
+    // Set the listener to be invoked when two or more regions are detected.
+    int setListener(in ITargetRegionListener listener);
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/scan/ITargetRegionListener.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/scan/ITargetRegionListener.aidl
index 7d3d8b9..9d6aa8e 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/scan/ITargetRegionListener.aidl
@@ -13,10 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.scan;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ITargetRegionListener {
+    void onDetectTargetRegion(in Bundle detectTargetRegions);
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/scan/ITkgsInfo.aidl
similarity index 68%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/scan/ITkgsInfo.aidl
index 7d3d8b9..f25952c 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/scan/ITkgsInfo.aidl
@@ -13,10 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.scan;
+
+import android.media.tv.extension.scan.ITkgsInfoListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface ITkgsInfo {
+     int setPrefServiceList(String prefServiceList);
+     int setTkgsInfoListener(in ITkgsInfoListener listener);
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/scan/ITkgsInfoListener.aidl
similarity index 71%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/scan/ITkgsInfoListener.aidl
index 7d3d8b9..e3dcf2d 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/scan/ITkgsInfoListener.aidl
@@ -13,10 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.scan;
+
+/**
+ * @hide
+ */
+oneway interface ITkgsInfoListener {
+    void onServiceList(in String[] serviceList);
+    void onTableVersionUpdate(int tableVersion);
+    void onUserMessage(String strMessage);
 }
diff --git a/media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdate.aidl b/media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdate.aidl
new file mode 100644
index 0000000..bda60ed
--- /dev/null
+++ b/media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdate.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.media.tv.extension.scanbsu;
+
+import android.media.tv.extension.scanbsu.IScanBackgroundServiceUpdateListener;
+
+/**
+ * @hide
+ */
+interface IScanBackgroundServiceUpdate {
+    // Set the listener for background service update
+    // receives notifications for svl/tsl/nwl update during background service update.
+    void addBackgroundServiceUpdateListener(String clientToken,
+        in IScanBackgroundServiceUpdateListener listener);
+    // Remove the listener for background service update to stop receiving notifications
+    // for svl/tsl/nwl update during background service update.
+    void removeBackgroundServiceUpdateListener(in IScanBackgroundServiceUpdateListener listener);
+}
diff --git a/media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdateListener.aidl b/media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdateListener.aidl
new file mode 100644
index 0000000..d9bcbed
--- /dev/null
+++ b/media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdateListener.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.extension.scanbsu;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IScanBackgroundServiceUpdateListener {
+    // On background service update add/delete/update svl records.
+    void onChannelListUpdate(String sessionToken, out Bundle[] updateInfos);
+    // On background service update add/delete/update nwl records.
+    void onNetworkListUpdate(String sessionToken, out Bundle[] updateInfos);
+    // On background service update add/delete/update tsl records.
+    void onTransportStreamingListUpdate(String sessionToken, out Bundle[] updateInfos);
+}
diff --git a/media/java/android/media/tv/extension/screenmode/IScreenModeSettings.aidl b/media/java/android/media/tv/extension/screenmode/IScreenModeSettings.aidl
new file mode 100644
index 0000000..57f3b4a
--- /dev/null
+++ b/media/java/android/media/tv/extension/screenmode/IScreenModeSettings.aidl
@@ -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 android.media.tv.extension.screenmode;
+
+/**
+ * @hide
+ */
+interface IScreenModeSettings {
+    // Set screen mode information using a JSON string.
+    void setScreenModeSettings(String sessionToken, String setting);
+    // Get the overscan index which TIS session is applied.
+    int getOverScanIndex(String sessionToken);
+    // Get status that TIS session is support overscan or not.
+    boolean getSupportApplyOverScan(String sessionToken);
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/servicedb/IChannelListTransfer.aidl
similarity index 62%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/servicedb/IChannelListTransfer.aidl
index 7d3d8b9..cb6aecc 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/servicedb/IChannelListTransfer.aidl
@@ -13,10 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.servicedb;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * @hide
+ */
+interface IChannelListTransfer {
+    // Parse XML file and import Channels information.
+    void importChannelList(in ParcelFileDescriptor pfd);
+    // Get Channels information for export and create XML file.
+    void exportChannelList(in ParcelFileDescriptor pfd);
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/servicedb/IServiceList.aidl
similarity index 60%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/servicedb/IServiceList.aidl
index 7d3d8b9..51daa80 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/servicedb/IServiceList.aidl
@@ -13,10 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.servicedb;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IServiceList {
+    // Get a list of the Service list IDs quivalent to COLUMN_CHANNEL_LIST_ID
+    // in the Channels table of TvProvider.
+    String[] getServiceListIds();
+    // Get the information associated with the Service list.
+    Bundle getServiceListInfo(String serviceListId, in String[] keys);
 }
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListEdit.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListEdit.aidl
new file mode 100644
index 0000000..1b1577f
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListEdit.aidl
@@ -0,0 +1,81 @@
+/*
+ * 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.media.tv.extension.servicedb;
+
+import android.media.tv.extension.servicedb.IServiceListEditListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IServiceListEdit {
+    // Open in edit mode. Must call close() after edit is done.
+    int open(IServiceListEditListener listener);
+    // Method to close in edit mode.
+    int close();
+    // Method to commit changes made to service database.
+    int commit();
+    // Method to commit and close the changes.
+    int userEditCommit();
+
+    // Get a service/transportStream/Network/Satellite record information specified by
+    // serviceInfoId and keys from tvdb.
+    Bundle getServiceInfoFromDatabase(String serviceInfoId, in String[] keys);
+    // Get a list of all service records' information specified by serviceListId and keys from tvdb.
+    Bundle getServiceInfoListFromDatabase(String serviceListId, in String[] keys);
+    // Get a list of all service info IDs in the service list of serviceListId from tvdb.
+    String[] getServiceInfoIdsFromDatabase(String inServiceListId);
+    // Update a service information by the contents of serviceInfo;
+    int updateServiceInfoFromDatabase(in Bundle updateServiceInfo);
+    // Update all service information by the contents of serviceInfoList.
+    int updateServiceInfoByListFromDatabase(in Bundle[] updateServiceInfoList);
+    // Remove a service information of the serviceInfoId from the service list.
+    int removeServiceInfoFromDatabase(String serviceInfoId);
+    // Remove all service information of the serviceInfoId from the service list.
+    int removeServiceInfoByListFromDatabase(in String[] serviceInfoIdList);
+    // Get a list of the Service list IDs which is equivalent to COLUMN_CHANNEL_LIST_ID
+    // in Channels table from tv db.
+    String[] getServiceListChannelIds();
+    // Get the information associated with the Service list Channel id.
+    Bundle getServiceListInfoByChannelId(String serviceListChannelId, in String[] keys);
+
+    // Get a list of transportStream records' information specified by serviceListId and keys.
+    Bundle getTransportStreamInfoList(String serviceListId, in String[] keys);
+    // Get a list of transportStream records' information specified by serviceListId and keys
+    // from work db.
+    Bundle getTransportStreamInfoListForce(String serviceListId, in String[] keys);
+
+    // Get a list of network records' information specified by serviceListId and keys.
+    Bundle getNetworkInfoList(String serviceListId, in String[] keys);
+    // Get a list of satellite records' information specified by serviceListId and keys.
+    Bundle getSatelliteInfoList(String serviceListId, in String[] keys);
+
+    // Decompress whole bundle value of single service/transportStream/Network/Satellite record.
+    // RecordInfoBundle:a single record got from database by getServiceInfoFromDatabase()
+    String toRecordInfoByType(in Bundle recordInfoBundle, String recordType);
+    // Set channels(tv.db) modified result to middleware database(SVL/TSL/NWL/SATL).
+    int putRecordIdList(String serviceListId, in Bundle recordIdListBundle, int optType);
+
+    // Add predefined ServiceListInfo of Hotbird 13E in scan two satellite scene EU region
+    // following by commit().
+    String addPredefinedServiceListInfo(int broadcastType, String serviceListType,
+        String serviceListPrefix, String countryCode, int operatorId);
+    // Add predefined channels of Hotbird 13E in scan two satellite scene EU region.
+    int addPredefinedChannelList(String serviceListId, in Bundle[] predefinedListBundle);
+    // Add predefined satellite info of Hotbird 13E in scan two satellite scene EU region.
+    int addPredefinedSatInfo(String serviceListId, in Bundle predefinedSatInfoBundle);
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/servicedb/IServiceListEditListener.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/servicedb/IServiceListEditListener.aidl
index 7d3d8b9..e227eda 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListEditListener.aidl
@@ -13,10 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.servicedb;
+
+/**
+ * @hide
+ */
+oneway interface IServiceListEditListener {
+    void onCompleted(int requestId, int result);
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/servicedb/IServiceListExportListener.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/servicedb/IServiceListExportListener.aidl
index 7d3d8b9..c57e8f9 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListExportListener.aidl
@@ -13,10 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.servicedb;
+
+/**
+ * @hide
+ */
+oneway interface IServiceListExportListener {
+    void onExported(int exportResult);
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/servicedb/IServiceListExportSession.aidl
similarity index 62%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/servicedb/IServiceListExportSession.aidl
index 7d3d8b9..fcde581 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListExportSession.aidl
@@ -13,10 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.servicedb;
+
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * @hide
+ */
+interface IServiceListExportSession {
+    // Start export service list with reserved parameters.
+    int exportServiceList(in ParcelFileDescriptor pfd, in Bundle exportParams);
+    // Release export resources.
+    int release();
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/servicedb/IServiceListImportListener.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/servicedb/IServiceListImportListener.aidl
index 7d3d8b9..abd8320 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListImportListener.aidl
@@ -13,10 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
-}
+package android.media.tv.extension.servicedb;
+
+/**
+ * @hide
+ */
+interface IServiceListImportListener {
+    void onImported(int importResult);
+    void onPreloaded(int preloadResult);
+}
\ No newline at end of file
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListImportSession.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListImportSession.aidl
new file mode 100644
index 0000000..1f1ae01
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListImportSession.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.media.tv.extension.servicedb;
+
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * @hide
+ */
+interface IServiceListImportSession {
+    // Start import service list. Should call after preload and before release.
+    int importServiceList(in ParcelFileDescriptor pfd, in Bundle importParams);
+    // Preparing for import.
+    int preload(in ParcelFileDescriptor pfd);
+    // Release import resources.
+    int release();
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListListener.aidl
similarity index 74%
rename from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
rename to media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListListener.aidl
index 7d3d8b9..7c9c5c8 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListListener.aidl
@@ -13,10 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.servicedb;
+
+/**
+ * @hide
+ */
+oneway interface IServiceListSetChannelListListener {
+    void onCompleted(int setChannelListResult);
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListSession.aidl
similarity index 61%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListSession.aidl
index 7d3d8b9..b0527b3 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListSession.aidl
@@ -13,10 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.servicedb;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IServiceListSetChannelListSession {
+    // Set channelList with channelinfo bundles, serviceListInfo, and operation type.
+    int setChannelList(in Bundle[] channelsInfo, in Bundle ServiceListInfoBundle, int optType);
+    // Release set channellist resources.
+    int release();
 }
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListTransferInterface.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListTransferInterface.aidl
new file mode 100644
index 0000000..91fb157
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListTransferInterface.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.extension.servicedb;
+
+import android.media.tv.extension.servicedb.IServiceListExportListener;
+import android.media.tv.extension.servicedb.IServiceListImportListener;
+import android.media.tv.extension.servicedb.IServiceListSetChannelListListener;
+import android.os.IBinder;
+
+/**
+ * @hide
+ */
+interface IServiceListTransferInterface {
+    IBinder createExportSession(in IServiceListExportListener listener);
+    IBinder createImportSession(in IServiceListImportListener listener);
+    IBinder createSetChannelListSession(in IServiceListSetChannelListListener listener);
+}
diff --git a/media/java/android/media/tv/extension/teletext/IDataServiceSignalInfo.aidl b/media/java/android/media/tv/extension/teletext/IDataServiceSignalInfo.aidl
new file mode 100644
index 0000000..a3725e4
--- /dev/null
+++ b/media/java/android/media/tv/extension/teletext/IDataServiceSignalInfo.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.media.tv.extension.teletext;
+
+import android.media.tv.extension.teletext.IDataServiceSignalInfoListener;
+import android.os.Bundle;
+
+
+/**
+ * @hide
+ */
+interface IDataServiceSignalInfo {
+     // Get Teletext data service signal information.
+     Bundle getDataServiceSignalInfo(String sessionToken);
+     // Add a listener that receives notifications of teletext running information.
+     void addDataServiceSignalInfoListener(String clientToken,
+        IDataServiceSignalInfoListener listener);
+     // Remove a listener that receives notifications of Teletext running information.
+     void removeDataServiceSignalInfoListener(String clientToken,
+        IDataServiceSignalInfoListener listener);
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/teletext/IDataServiceSignalInfoListener.aidl
similarity index 72%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/teletext/IDataServiceSignalInfoListener.aidl
index 7d3d8b9..0e99bf5 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/teletext/IDataServiceSignalInfoListener.aidl
@@ -13,10 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.teletext;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IDataServiceSignalInfoListener {
+    void onDataServiceSignalInfoChanged (String sessionToken, in Bundle changedSignalInfo);
 }
diff --git a/media/java/android/media/tv/extension/teletext/ITeletextPageSubCode.aidl b/media/java/android/media/tv/extension/teletext/ITeletextPageSubCode.aidl
new file mode 100644
index 0000000..c96ffc0
--- /dev/null
+++ b/media/java/android/media/tv/extension/teletext/ITeletextPageSubCode.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.media.tv.extension.teletext;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface ITeletextPageSubCode {
+    // Get Teletext page number
+    Bundle getTeletextPageNumber(String sessionToken);
+    // Set Teletext page number.
+    void setTeleltextPageNumber(String sessionToken, int pageNumber);
+    // Get Teletext sub page number.
+    Bundle getTeletextPageSubCode(String sessionToken);
+    // Set Teletext sub page number.
+    void setTeletextPageSubCode(String sessionToken, int pageSubCode);
+    // Get Teletext TopInfo.
+    Bundle getTeletextHasTopInfo(String sessionToken);
+    // Get Teletext TopBlockList.
+    Bundle getTeletextTopBlockList(String sessionToken);
+    // Get Teletext TopGroupList.
+    Bundle getTeletextTopGroupList(String sessionToken, int indexGroup);
+    // Get Teletext TopPageList.
+    Bundle getTeletextTopPageList(String sessionToken, int indexPage);
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/tune/IChannelTunedInterface.aidl
similarity index 67%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/tune/IChannelTunedInterface.aidl
index 7d3d8b9..88e5084 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/tune/IChannelTunedInterface.aidl
@@ -13,10 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.tune;
+
+import android.media.tv.extension.tune.IChannelTunedListener;
+
+/*
+* @hide
+*/
+interface IChannelTunedInterface {
+    void addChannelTunedListener(in IChannelTunedListener listener);
+    void removeChannelTunedListener(in IChannelTunedListener listener);
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/tune/IChannelTunedListener.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/tune/IChannelTunedListener.aidl
index 7d3d8b9..4687546 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/tune/IChannelTunedListener.aidl
@@ -13,10 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.tune;
+
+import android.os.Bundle;
+
+/*
+* @hide
+*/
+oneway interface IChannelTunedListener {
+    void onChannelTuned(String sessionToken, in Bundle channelTunedInfo);
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/media/java/android/media/tv/extension/tune/IMuxTune.aidl
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to media/java/android/media/tv/extension/tune/IMuxTune.aidl
index 7d3d8b9..4e9dbda 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/media/java/android/media/tv/extension/tune/IMuxTune.aidl
@@ -13,10 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.media.tv.extension.tune;
+
+import android.media.tv.extension.tune.IMuxTuneSession;
+
+/**
+* @hide
+*/
+interface IMuxTune {
+    IMuxTuneSession createSession(int broadcastType, String clientToken);
 }
diff --git a/media/java/android/media/tv/extension/tune/IMuxTuneSession.aidl b/media/java/android/media/tv/extension/tune/IMuxTuneSession.aidl
new file mode 100644
index 0000000..5ad72b4
--- /dev/null
+++ b/media/java/android/media/tv/extension/tune/IMuxTuneSession.aidl
@@ -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 android.media.tv.extension.tune;
+
+import android.os.Bundle;
+
+/**
+* @hide
+*/
+interface IMuxTuneSession {
+    // Start mux tune with tune params.
+    void start(int broadcastType, int frequency, int brandwith, in Bundle muxTuneParams);
+    // Stop mux tune.
+    void stop();
+    // Release muxtune resources.
+    void release();
+    // Get the session token created by TIS to identify different sessions.
+    String getSessionToken();
+}
diff --git a/media/java/android/media/tv/flags/media_tv.aconfig b/media/java/android/media/tv/flags/media_tv.aconfig
index 4b832ae..3451dfc 100644
--- a/media/java/android/media/tv/flags/media_tv.aconfig
+++ b/media/java/android/media/tv/flags/media_tv.aconfig
@@ -93,7 +93,7 @@
     name: "set_resource_holder_retain"
     is_exported: true
     namespace: "media_tv"
-    description: "Feature flag to add setResourceHolderRetain api to MediaCas and Tuner JAVA."
+    description: "Feature flag to add setResourceOwnershipRetention api to MediaCas and Tuner JAVA."
     bug: "372973197"
 }
 
@@ -112,3 +112,11 @@
     description : "Feature flag to enable APIs for applying picture profiles"
     bug: "337330263"
 }
+
+flag {
+    name: "hdmi_control_collect_physical_address"
+    is_exported: true
+    namespace: "media_tv"
+    description: "Collect physical address from HDMI-CEC messages in metrics"
+    bug: "376001043"
+}
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index b1adb77..7f7a239 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -757,14 +757,14 @@
      * scenario, when both resource holder and resource challenger have same processId and same
      * priority.
      *
-     * @param resourceHolderRetain Set to true to allow the resource holder to retain ownership, or
-     *     false to allow the resource challenger to acquire the resource. If not explicitly set,
-     *     resourceHolderRetain is set to false.
+     * @param enabled Set to {@code true} to allow the resource holder to retain ownership,
+     *     or false to allow the resource challenger to acquire the resource.
+     *     If not explicitly set, enabled is set to {@code false}.
      */
     @FlaggedApi(FLAG_SET_RESOURCE_HOLDER_RETAIN)
     @RequiresPermission(android.Manifest.permission.TUNER_RESOURCE_ACCESS)
-    public void setResourceHolderRetain(boolean resourceHolderRetain) {
-        mTunerResourceManager.setResourceHolderRetain(mClientId, resourceHolderRetain);
+    public void setResourceOwnershipRetention(boolean enabled) {
+        mTunerResourceManager.setResourceOwnershipRetention(mClientId, enabled);
     }
 
     /**
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
index be65ad9..2ed642e 100644
--- a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresFeature;
+import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
@@ -227,15 +228,16 @@
      * scenario, when both resource holder and resource challenger have same processId and same
      * priority.
      *
-     * @param clientId The client id used to set ownership of resource to owner in case of resource
+     * @param clientId The client id used to set ownership of resource in case of resource
      *     challenger situation.
-     * @param resourceHolderRetain Set to true to allow the resource holder to retain ownership, or
-     *     false to allow the resource challenger to acquire the resource. If not explicitly set,
-     *     resourceHolderRetain is set to false.
+     * @param enabled Set to {@code true} to allow the resource holder to retain ownership,
+     *     or false to allow the resource challenger to acquire the resource.
+     *     If not explicitly set, enabled is set to {@code false}.
      */
-    public void setResourceHolderRetain(int clientId, boolean resourceHolderRetain) {
+    @RequiresPermission(android.Manifest.permission.TUNER_RESOURCE_ACCESS)
+    public void setResourceOwnershipRetention(int clientId, boolean enabled) {
         try {
-            mService.setResourceHolderRetain(clientId, resourceHolderRetain);
+            mService.setResourceOwnershipRetention(clientId, enabled);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
index c57be1b0..50f9fe5 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
+++ b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
@@ -156,12 +156,13 @@
      * scenario, when both Resource Holder and Resource Challenger have same processId and same
      * priority.
      *
-     * @param clientId The resourceHolderRetain of the client is updated using client ID.
-     * @param resourceHolderRetain set to true to allow the Resource Holder to retain ownership, or
-     *     false to allow the Resource Challenger to acquire the resource. If not explicitly set,
-     *     resourceHolderRetain is set to false.
+     * @param clientId The client id used to set ownership of resource in case of resource
+     *     challenger situation.
+     * @param enabled Set to {@code true} to allow the Resource Holder to retain ownership,
+     *     or false to allow the Resource Challenger to acquire the resource.
+     *     If not explicitly set, enabled is set to {@code false}.
      */
-    void setResourceHolderRetain(int clientId, boolean resourceHolderRetain);
+    void setResourceOwnershipRetention(int clientId, boolean enabled);
 
     /*
      * This API is used by the Tuner framework to request a frontend from the TunerHAL.
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index 88c1c43..ec336d5 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -27,6 +27,7 @@
 import android.hardware.ICameraServiceListener;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.CameraMetadataInfo;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
@@ -217,7 +218,7 @@
          * android.hardware.camera2.CaptureResultExtras)
          */
         @Override
-        public void onResultReceived(CameraMetadataNative result, CaptureResultExtras resultExtras,
+        public void onResultReceived(CameraMetadataInfo result, CaptureResultExtras resultExtras,
                 PhysicalCaptureResultInfo physicalResults[]) throws RemoteException {
             // TODO Auto-generated method stub
         }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 3758c51..7d1e5f8 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -33,6 +33,7 @@
 import android.hardware.ICameraService;
 import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraMetadataInfo;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
@@ -141,7 +142,7 @@
          * android.hardware.camera2.impl.CameraMetadataNative,
          * android.hardware.camera2.CaptureResultExtras)
          */
-        public void onResultReceived(CameraMetadataNative result, CaptureResultExtras resultExtras,
+        public void onResultReceived(CameraMetadataInfo result, CaptureResultExtras resultExtras,
                 PhysicalCaptureResultInfo physicalResults[]) throws RemoteException {
             // TODO Auto-generated method stub
 
@@ -186,10 +187,14 @@
         }
     }
 
-    class IsMetadataNotEmpty implements ArgumentMatcher<CameraMetadataNative> {
+    class IsMetadataNotEmpty implements ArgumentMatcher<CameraMetadataInfo> {
         @Override
-        public boolean matches(CameraMetadataNative obj) {
-            return !obj.isEmpty();
+        public boolean matches(CameraMetadataInfo obj) {
+            if (obj.getTag() == CameraMetadataInfo.metadata) {
+                return !(obj.getMetadata().isEmpty());
+            } else {
+                return (obj.getFmqSize() != 0);
+            }
         }
     }
 
diff --git a/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java b/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
index c9807e6..58aa56b 100644
--- a/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
+++ b/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
@@ -46,7 +46,7 @@
     }
 
     @Override
-    public void stop() throws RemoteException {
+    public void stop(@StopReason int stopReason) throws RemoteException {
         // Pass along to the client's callback wrapper.
         mIMediaProjectionCallback.onStop();
     }
diff --git a/native/android/Android.bp b/native/android/Android.bp
index da29c49..cd6de5a 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -55,6 +55,7 @@
         "surface_control_input_receiver.cpp",
         "choreographer.cpp",
         "configuration.cpp",
+        "display_luts.cpp",
         "dynamic_instrumentation_manager.cpp",
         "hardware_buffer_jni.cpp",
         "input.cpp",
diff --git a/native/android/OWNERS b/native/android/OWNERS
index 9a3527d..f0db2ea 100644
--- a/native/android/OWNERS
+++ b/native/android/OWNERS
@@ -31,3 +31,4 @@
 
 # PerformanceHint
 per-file performance_hint.cpp = file:/ADPF_OWNERS
+per-file thermal.cpp = file:/ADPF_OWNERS
diff --git a/native/android/display_luts.cpp b/native/android/display_luts.cpp
new file mode 100644
index 0000000..179a32b
--- /dev/null
+++ b/native/android/display_luts.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "DisplayLuts"
+
+#include <android/display_luts.h>
+#include <display_luts_private.h>
+#include <utils/Log.h>
+
+#include <cmath>
+
+#define ADISPLAYLUTS_BUFFER_LENGTH_LIMIT (100000)
+
+#define CHECK_NOT_NULL(name) \
+    LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument");
+
+ADisplayLutsEntry* ADisplayLutsEntry_createEntry(float* buffer, int32_t length, int32_t dimension,
+                                                 int32_t key) {
+    CHECK_NOT_NULL(buffer);
+    LOG_ALWAYS_FATAL_IF(length >= ADISPLAYLUTS_BUFFER_LENGTH_LIMIT,
+                        "the lut raw buffer length is too big to handle");
+    if (dimension != ADISPLAYLUTS_ONE_DIMENSION && dimension != ADISPLAYLUTS_THREE_DIMENSION) {
+        LOG_ALWAYS_FATAL("the lut dimension is be either 1 or 3");
+    }
+    int32_t size = 0;
+    if (dimension == ADISPLAYLUTS_THREE_DIMENSION) {
+        LOG_ALWAYS_FATAL_IF(length % 3 != 0, "the 3d lut raw buffer is not divisible by 3");
+        int32_t lengthPerChannel = length / 3;
+        float sizeForDim = std::cbrt(static_cast<float>(lengthPerChannel));
+        LOG_ALWAYS_FATAL_IF(sizeForDim != (int)(sizeForDim),
+                            "the 3d lut buffer length is incorrect");
+        size = (int)sizeForDim;
+    } else {
+        size = length;
+    }
+    LOG_ALWAYS_FATAL_IF(size < 2, "the lut size for each dimension is too small");
+
+    ADisplayLutsEntry* entry = new ADisplayLutsEntry();
+    entry->buffer.data.resize(length);
+    std::copy(buffer, buffer + length, entry->buffer.data.begin());
+    entry->properties = {dimension, size, key};
+
+    entry->incStrong((void*)ADisplayLutsEntry_createEntry);
+    return static_cast<ADisplayLutsEntry*>(entry);
+}
+
+void ADisplayLutsEntry_destroy(ADisplayLutsEntry* entry) {
+    if (entry != NULL) {
+        entry->decStrong((void*)ADisplayLutsEntry_createEntry);
+    }
+}
+
+ADisplayLuts_Dimension ADisplayLutsEntry_getDimension(const ADisplayLutsEntry* entry) {
+    CHECK_NOT_NULL(entry);
+    return static_cast<ADisplayLuts_Dimension>(entry->properties.dimension);
+}
+
+int32_t ADisplayLutsEntry_getSize(const ADisplayLutsEntry* entry) {
+    CHECK_NOT_NULL(entry);
+    return entry->properties.size;
+}
+
+ADisplayLuts_SamplingKey ADisplayLutsEntry_getSamplingKey(const ADisplayLutsEntry* entry) {
+    CHECK_NOT_NULL(entry);
+    return static_cast<ADisplayLuts_SamplingKey>(entry->properties.samplingKey);
+}
+
+const float* ADisplayLutsEntry_getBuffer(const ADisplayLutsEntry* _Nonnull entry) {
+    CHECK_NOT_NULL(entry);
+    return entry->buffer.data.data();
+}
+
+ADisplayLuts* ADisplayLuts_create() {
+    ADisplayLuts* luts = new ADisplayLuts();
+    if (luts == NULL) {
+        delete luts;
+        return NULL;
+    }
+    luts->incStrong((void*)ADisplayLuts_create);
+    return static_cast<ADisplayLuts*>(luts);
+}
+
+void ADisplayLuts_clearLuts(ADisplayLuts* luts) {
+    for (auto& entry : luts->entries) {
+        entry->decStrong((void*)ADisplayLuts_setEntries); // Decrement ref count
+    }
+    luts->entries.clear();
+    luts->offsets.clear();
+    luts->totalBufferSize = 0;
+}
+
+void ADisplayLuts_destroy(ADisplayLuts* luts) {
+    if (luts != NULL) {
+        ADisplayLuts_clearLuts(luts);
+        luts->decStrong((void*)ADisplayLuts_create);
+    }
+}
+
+void ADisplayLuts_setEntries(ADisplayLuts* luts, ADisplayLutsEntry** entries, int32_t numEntries) {
+    CHECK_NOT_NULL(luts);
+    // always clear the previously set lut(s)
+    ADisplayLuts_clearLuts(luts);
+
+    // do nothing
+    if (!entries || numEntries == 0) {
+        return;
+    }
+
+    LOG_ALWAYS_FATAL_IF(numEntries > 2, "The number of entries should be not over 2!");
+    if (numEntries == 2 && entries[0]->properties.dimension != ADISPLAYLUTS_ONE_DIMENSION &&
+        entries[1]->properties.dimension != ADISPLAYLUTS_THREE_DIMENSION) {
+        LOG_ALWAYS_FATAL("The entries should be 1D and 3D in order!");
+    }
+
+    luts->offsets.reserve(numEntries);
+    luts->entries.reserve(numEntries);
+    for (int32_t i = 0; i < numEntries; i++) {
+        luts->offsets.emplace_back(luts->totalBufferSize);
+        luts->totalBufferSize += entries[i]->buffer.data.size();
+        luts->entries.emplace_back(entries[i]);
+        luts->entries.back()->incStrong((void*)ADisplayLuts_setEntries);
+    }
+}
\ No newline at end of file
diff --git a/native/android/dynamic_instrumentation_manager.cpp b/native/android/dynamic_instrumentation_manager.cpp
index d9bacb1..5322136 100644
--- a/native/android/dynamic_instrumentation_manager.cpp
+++ b/native/android/dynamic_instrumentation_manager.cpp
@@ -65,7 +65,7 @@
 }
 
 void ADynamicInstrumentationManager_TargetProcess_destroy(
-        ADynamicInstrumentationManager_TargetProcess* instance) {
+        const ADynamicInstrumentationManager_TargetProcess* instance) {
     delete instance;
 }
 
@@ -96,7 +96,7 @@
 }
 
 void ADynamicInstrumentationManager_MethodDescriptor_destroy(
-        ADynamicInstrumentationManager_MethodDescriptor* instance) {
+        const ADynamicInstrumentationManager_MethodDescriptor* instance) {
     delete instance;
 }
 
@@ -112,29 +112,29 @@
 }
 
 const char* ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerPath(
-        ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
+        const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
     return instance->containerPath.c_str();
 }
 
 uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerOffset(
-        ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
+        const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
     return instance->containerOffset;
 }
 
 uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOffset(
-        ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
+        const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
     return instance->methodOffset;
 }
 
 void ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy(
-        ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
+        const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
     delete instance;
 }
 
 int32_t ADynamicInstrumentationManager_getExecutableMethodFileOffsets(
         const ADynamicInstrumentationManager_TargetProcess* targetProcess,
         const ADynamicInstrumentationManager_MethodDescriptor* methodDescriptor,
-        ADynamicInstrumentationManager_ExecutableMethodFileOffsets** out) {
+        const ADynamicInstrumentationManager_ExecutableMethodFileOffsets** out) {
     android::os::instrumentation::TargetProcess targetProcessParcel;
     targetProcessParcel.uid = targetProcess->uid;
     targetProcessParcel.pid = targetProcess->pid;
diff --git a/native/android/include_platform/android/dynamic_instrumentation_manager.h b/native/android/include_platform/android/dynamic_instrumentation_manager.h
index 6c46288..ab9f370 100644
--- a/native/android/include_platform/android/dynamic_instrumentation_manager.h
+++ b/native/android/include_platform/android/dynamic_instrumentation_manager.h
@@ -51,7 +51,7 @@
  * @param instance returned from ADynamicInstrumentationManager_TargetProcess_create.
  */
 void ADynamicInstrumentationManager_TargetProcess_destroy(
-        ADynamicInstrumentationManager_TargetProcess* _Nonnull instance) __INTRODUCED_IN(36);
+        const ADynamicInstrumentationManager_TargetProcess* _Nonnull instance) __INTRODUCED_IN(36);
 
 /**
  * Initializes an ADynamicInstrumentationManager_MethodDescriptor. Caller must clean up when they
@@ -74,7 +74,8 @@
  * @param instance returned from ADynamicInstrumentationManager_MethodDescriptor_create.
  */
 void ADynamicInstrumentationManager_MethodDescriptor_destroy(
-        ADynamicInstrumentationManager_MethodDescriptor* _Nonnull instance) __INTRODUCED_IN(36);
+        const ADynamicInstrumentationManager_MethodDescriptor* _Nonnull instance)
+        __INTRODUCED_IN(36);
 
 /**
  * Get the containerPath calculated by
@@ -83,7 +84,7 @@
  * @return The OS path of the containing file.
  */
 const char* _Nullable ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerPath(
-        ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
+        const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
         __INTRODUCED_IN(36);
 /**
  * Get the containerOffset calculated by
@@ -92,7 +93,7 @@
  * @return The offset of the containing file within the process' memory.
  */
 uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerOffset(
-        ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
+        const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
         __INTRODUCED_IN(36);
 /**
  * Get the methodOffset calculated by ADynamicInstrumentationManager_getExecutableMethodFileOffsets.
@@ -100,7 +101,7 @@
  * @return The offset of the method within the containing file.
  */
 uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOffset(
-        ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
+        const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
         __INTRODUCED_IN(36);
 /**
  * Clean up an ADynamicInstrumentationManager_ExecutableMethodFileOffsets.
@@ -108,7 +109,7 @@
  * @param instance returned from ADynamicInstrumentationManager_getExecutableMethodFileOffsets.
  */
 void ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy(
-        ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
+        const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
         __INTRODUCED_IN(36);
 /**
  * Provides ART metadata about the described java method within the target process.
@@ -124,7 +125,7 @@
 int32_t ADynamicInstrumentationManager_getExecutableMethodFileOffsets(
         const ADynamicInstrumentationManager_TargetProcess* _Nonnull targetProcess,
         const ADynamicInstrumentationManager_MethodDescriptor* _Nonnull methodDescriptor,
-        ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull* _Nullable out)
+        const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nullable* _Nonnull out)
         __INTRODUCED_IN(36);
 
 __END_DECLS
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 9da7bec..7f555a8 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -95,6 +95,15 @@
     AConfiguration_setTouchscreen;
     AConfiguration_setUiModeNight;
     AConfiguration_setUiModeType;
+    ADisplayLuts_create; # introduced=36
+    ADisplayLuts_setEntries; # introduced=36
+    ADisplayLuts_destroy; # introduced=36
+    ADisplayLutsEntry_createEntry; # introduced=36
+    ADisplayLutsEntry_getDimension; # introduced=36
+    ADisplayLutsEntry_getSize; # introduced=36
+    ADisplayLutsEntry_getSamplingKey; # introduced=36
+    ADisplayLutsEntry_getBuffer; # introduced=36
+    ADisplayLutsEntry_destroy; # introduced=36
     AInputEvent_getDeviceId;
     AInputEvent_getSource;
     AInputEvent_getType;
@@ -300,6 +309,7 @@
     ASurfaceTransaction_setHdrMetadata_smpte2086; # introduced=29
     ASurfaceTransaction_setExtendedRangeBrightness; # introduced=UpsideDownCake
     ASurfaceTransaction_setDesiredHdrHeadroom; # introduced=VanillaIceCream
+    ASurfaceTransaction_setLuts; # introduced=36
     ASurfaceTransaction_setOnComplete; # introduced=29
     ASurfaceTransaction_setOnCommit; # introduced=31
     ASurfaceTransaction_setPosition; # introduced=31
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index c67e93c..883e139 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -881,6 +881,8 @@
             case hal::SessionMode::GRAPHICS_PIPELINE:
                 traceGraphicsPipeline(isEnabled);
                 break;
+            default:
+                break;
         }
     }
 }
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 698bc84..fc64e9b 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -14,12 +14,15 @@
  * limitations under the License.
  */
 
+#include <android/gui/LutProperties.h>
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <android/native_window.h>
 #include <android/surface_control.h>
 #include <android/surface_control_jni.h>
 #include <android_runtime/android_view_SurfaceControl.h>
 #include <configstore/Utils.h>
+#include <cutils/ashmem.h>
+#include <display_luts_private.h>
 #include <gui/HdrMetadata.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/Surface.h>
@@ -53,6 +56,14 @@
 static_assert(static_cast<int>(ADATASPACE_DISPLAY_P3) ==
               static_cast<int>(HAL_DATASPACE_DISPLAY_P3));
 static_assert(static_cast<int>(ADATASPACE_BT2020_PQ) == static_cast<int>(HAL_DATASPACE_BT2020_PQ));
+static_assert(static_cast<int>(ADISPLAYLUTS_ONE_DIMENSION) ==
+              static_cast<int>(android::gui::LutProperties::Dimension::ONE_D));
+static_assert(static_cast<int>(ADISPLAYLUTS_THREE_DIMENSION) ==
+              static_cast<int>(android::gui::LutProperties::Dimension::THREE_D));
+static_assert(static_cast<int>(ADISPLAYLUTS_SAMPLINGKEY_RGB) ==
+              static_cast<int>(android::gui::LutProperties::SamplingKey::RGB));
+static_assert(static_cast<int>(ADISPLAYLUTS_SAMPLINGKEY_MAX_RGB) ==
+              static_cast<int>(android::gui::LutProperties::SamplingKey::MAX_RGB));
 
 Transaction* ASurfaceTransaction_to_Transaction(ASurfaceTransaction* aSurfaceTransaction) {
     return reinterpret_cast<Transaction*>(aSurfaceTransaction);
@@ -693,6 +704,58 @@
     transaction->setDesiredHdrHeadroom(surfaceControl, desiredRatio);
 }
 
+void ASurfaceTransaction_setLuts(ASurfaceTransaction* aSurfaceTransaction,
+                                 ASurfaceControl* aSurfaceControl,
+                                 const struct ADisplayLuts* luts) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    int fd = -1;
+    std::vector<int32_t> offsets;
+    std::vector<int32_t> dimensions;
+    std::vector<int32_t> sizes;
+    std::vector<int32_t> samplingKeys;
+
+    if (luts) {
+        std::vector<float> buffer(luts->totalBufferSize);
+        int32_t count = luts->offsets.size();
+        offsets = luts->offsets;
+
+        dimensions.reserve(count);
+        sizes.reserve(count);
+        samplingKeys.reserve(count);
+        for (int32_t i = 0; i < count; i++) {
+            dimensions.emplace_back(luts->entries[i]->properties.dimension);
+            sizes.emplace_back(luts->entries[i]->properties.size);
+            samplingKeys.emplace_back(luts->entries[i]->properties.samplingKey);
+            std::copy(luts->entries[i]->buffer.data.begin(), luts->entries[i]->buffer.data.end(),
+                      buffer.begin() + offsets[i]);
+        }
+
+        // mmap
+        fd = ashmem_create_region("lut_shared_mem", luts->totalBufferSize * sizeof(float));
+        if (fd < 0) {
+            LOG_ALWAYS_FATAL("setLuts, ashmem_create_region() failed");
+            return;
+        }
+        void* ptr = mmap(nullptr, luts->totalBufferSize * sizeof(float), PROT_READ | PROT_WRITE,
+                         MAP_SHARED, fd, 0);
+        if (ptr == MAP_FAILED) {
+            LOG_ALWAYS_FATAL("setLuts, Failed to map the shared memory");
+            return;
+        }
+
+        memcpy(ptr, buffer.data(), luts->totalBufferSize * sizeof(float));
+        munmap(ptr, luts->totalBufferSize * sizeof(float));
+    }
+
+    transaction->setLuts(surfaceControl, base::unique_fd(fd), offsets, dimensions, sizes,
+                         samplingKeys);
+}
+
 void ASurfaceTransaction_setColor(ASurfaceTransaction* aSurfaceTransaction,
                                   ASurfaceControl* aSurfaceControl,
                                   float r, float g, float b, float alpha,
diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
index c5fb808..b006580 100644
--- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
+++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
@@ -73,13 +73,13 @@
     MOCK_METHOD(ScopedAStatus, closeSessionChannel, (), (override));
     MOCK_METHOD(ScopedAStatus, getCpuHeadroom,
                 (const ::aidl::android::os::CpuHeadroomParamsInternal& in_params,
-                 std::vector<float>* _aidl_return),
+                 std::optional<hal::CpuHeadroomResult>* _aidl_return),
                 (override));
     MOCK_METHOD(ScopedAStatus, getCpuHeadroomMinIntervalMillis, (int64_t* _aidl_return),
                 (override));
     MOCK_METHOD(ScopedAStatus, getGpuHeadroom,
                 (const ::aidl::android::os::GpuHeadroomParamsInternal& in_params,
-                 float* _aidl_return),
+                 std::optional<hal::GpuHeadroomResult>* _aidl_return),
                 (override));
     MOCK_METHOD(ScopedAStatus, getGpuHeadroomMinIntervalMillis, (int64_t* _aidl_return),
                 (override));
diff --git a/nfc/api/current.txt b/nfc/api/current.txt
index 7ae2eafa..0ee81cb 100644
--- a/nfc/api/current.txt
+++ b/nfc/api/current.txt
@@ -202,6 +202,7 @@
     method public boolean categoryAllowsForegroundPreference(String);
     method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public java.util.List<java.lang.String> getAidsForPreferredPaymentService();
     method public java.util.List<java.lang.String> getAidsForService(android.content.ComponentName, String);
+    method @FlaggedApi("android.nfc.enable_card_emulation_euicc") public int getDefaultNfcSubscriptionId();
     method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public CharSequence getDescriptionForPreferredPaymentService();
     method public static android.nfc.cardemulation.CardEmulation getInstance(android.nfc.NfcAdapter);
     method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public String getRouteDestinationForPreferredPaymentService();
@@ -232,6 +233,7 @@
     field @FlaggedApi("android.nfc.nfc_event_listener") public static final int NFC_INTERNAL_ERROR_NFC_CRASH_RESTART = 1; // 0x1
     field @FlaggedApi("android.nfc.nfc_event_listener") public static final int NFC_INTERNAL_ERROR_NFC_HARDWARE_ERROR = 2; // 0x2
     field @FlaggedApi("android.nfc.nfc_event_listener") public static final int NFC_INTERNAL_ERROR_UNKNOWN = 0; // 0x0
+    field @FlaggedApi("android.nfc.nfc_associated_role_services") public static final String PROPERTY_ALLOW_SHARED_ROLE_PRIORITY = "android.nfc.cardemulation.PROPERTY_ALLOW_SHARED_ROLE_PRIORITY";
     field @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_DEFAULT = 3; // 0x3
     field @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_DH = 0; // 0x0
     field @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE = 1; // 0x1
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index 15814ed..3ed9b76 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -57,17 +57,19 @@
   @FlaggedApi("android.nfc.nfc_oem_extension") public final class NfcOemExtension {
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void clearPreference();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int forceRoutingTableCommit();
-    method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public java.util.List<java.lang.String> getActiveNfceeList();
+    method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getActiveNfceeList();
+    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public long getMaxPausePollingTimeoutMills();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.nfc.RoutingStatus getRoutingStatus();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.List<android.nfc.NfcRoutingTableEntry> getRoutingTable();
+    method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public android.nfc.T4tNdefNfcee getT4tNdefNfcee();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean hasUserEnabledNfc();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isAutoChangeEnabled();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isTagPresent();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void maybeTriggerFirmwareUpdate();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void overwriteRoutingTable(int, int, int, int);
-    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void pausePolling(int);
+    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int pausePolling(long);
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcOemExtension.Callback);
-    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void resumePolling();
+    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int resumePolling();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setAutoChangeEnabled(boolean);
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void setControllerAlwaysOnMode(int);
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void synchronizeScreenState();
@@ -83,6 +85,8 @@
     field public static final int HCE_ACTIVATE = 1; // 0x1
     field public static final int HCE_DATA_TRANSFERRED = 2; // 0x2
     field public static final int HCE_DEACTIVATE = 3; // 0x3
+    field public static final int POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE = 2; // 0x2
+    field public static final int POLLING_STATE_CHANGE_SUCCEEDED = 1; // 0x1
     field public static final int STATUS_OK = 0; // 0x0
     field public static final int STATUS_UNKNOWN_ERROR = 1; // 0x1
   }
@@ -120,6 +124,11 @@
 
   @FlaggedApi("android.nfc.nfc_oem_extension") public abstract class NfcRoutingTableEntry {
     method public int getNfceeId();
+    method public int getType();
+    field public static final int TYPE_AID = 0; // 0x0
+    field public static final int TYPE_PROTOCOL = 1; // 0x1
+    field public static final int TYPE_SYSTEM_CODE = 3; // 0x3
+    field public static final int TYPE_TECHNOLOGY = 2; // 0x2
   }
 
   @FlaggedApi("android.nfc.nfc_oem_extension") public final class OemLogItems implements android.os.Parcelable {
@@ -179,6 +188,47 @@
     field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int TECHNOLOGY_V = 3; // 0x3
   }
 
+  @FlaggedApi("android.nfc.nfc_oem_extension") public final class T4tNdefNfcee {
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public int clearData();
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isOperationOngoing();
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isSupported();
+    method @Nullable @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public android.nfc.T4tNdefNfceeCcFileInfo readCcfile();
+    method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public byte[] readData(@IntRange(from=0, to=65535) int);
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public int writeData(@IntRange(from=0, to=65535) int, @NonNull byte[]);
+    field public static final int CLEAR_DATA_FAILED_INTERNAL = 0; // 0x0
+    field public static final int CLEAR_DATA_SUCCESS = 1; // 0x1
+    field public static final int WRITE_DATA_ERROR_CONNECTION_FAILED = -6; // 0xfffffffa
+    field public static final int WRITE_DATA_ERROR_EMPTY_PAYLOAD = -7; // 0xfffffff9
+    field public static final int WRITE_DATA_ERROR_INTERNAL = -1; // 0xffffffff
+    field public static final int WRITE_DATA_ERROR_INVALID_FILE_ID = -4; // 0xfffffffc
+    field public static final int WRITE_DATA_ERROR_INVALID_LENGTH = -5; // 0xfffffffb
+    field public static final int WRITE_DATA_ERROR_NDEF_VALIDATION_FAILED = -8; // 0xfffffff8
+    field public static final int WRITE_DATA_ERROR_NFC_NOT_ON = -3; // 0xfffffffd
+    field public static final int WRITE_DATA_ERROR_RF_ACTIVATED = -2; // 0xfffffffe
+    field public static final int WRITE_DATA_SUCCESS = 0; // 0x0
+  }
+
+  @FlaggedApi("android.nfc.nfc_oem_extension") public final class T4tNdefNfceeCcFileInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @IntRange(from=15, to=32767) public int getCcFileLength();
+    method @IntRange(from=0xffffffff, to=65535) public int getFileId();
+    method @IntRange(from=15, to=65535) public int getMaxReadLength();
+    method @IntRange(from=5, to=32767) public int getMaxSize();
+    method @IntRange(from=13, to=65535) public int getMaxWriteLength();
+    method public int getReadAccess();
+    method public int getVersion();
+    method public int getWriteAccess();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.nfc.T4tNdefNfceeCcFileInfo> CREATOR;
+    field public static final int READ_ACCESS_GRANTED_RESTRICTED = 128; // 0x80
+    field public static final int READ_ACCESS_GRANTED_UNRESTRICTED = 0; // 0x0
+    field public static final int VERSION_2_0 = 32; // 0x20
+    field public static final int VERSION_3_0 = 48; // 0x30
+    field public static final int WRITE_ACCESS_GRANTED_RESTRICTED = 128; // 0x80
+    field public static final int WRITE_ACCESS_GRANTED_UNRESTRICTED = 0; // 0x0
+    field public static final int WRITE_ACCESS_NOT_GRANTED = 255; // 0xff
+  }
+
 }
 
 package android.nfc.cardemulation {
@@ -186,14 +236,19 @@
   public final class CardEmulation {
     method @FlaggedApi("android.permission.flags.wallet_role_enabled") @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public static android.content.ComponentName getPreferredPaymentService(@NonNull android.content.Context);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<android.nfc.cardemulation.ApduServiceInfo> getServices(@NonNull String, int);
-    method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public void overrideRoutingTable(@NonNull android.app.Activity, int, int);
-    method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public void recoverRoutingTable(@NonNull android.app.Activity);
+    method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void overrideRoutingTable(@NonNull android.app.Activity, int, int);
+    method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void recoverRoutingTable(@NonNull android.app.Activity);
+    method @FlaggedApi("android.nfc.enable_card_emulation_euicc") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setDefaultNfcSubscriptionId(int);
     method @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setServiceEnabledForCategoryOther(@NonNull android.content.ComponentName, boolean);
     field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_ALREADY_SET = 3; // 0x3
     field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED = 1; // 0x1
     field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_INVALID_SERVICE = 2; // 0x2
     field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR = 4; // 0x4
     field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_OK = 0; // 0x0
+    field @FlaggedApi("android.nfc.enable_card_emulation_euicc") public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_INTERNAL_ERROR = 2; // 0x2
+    field @FlaggedApi("android.nfc.enable_card_emulation_euicc") public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_INVALID_SUBSCRIPTION_ID = 1; // 0x1
+    field @FlaggedApi("android.nfc.enable_card_emulation_euicc") public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_NOT_SUPPORTED = 3; // 0x3
+    field @FlaggedApi("android.nfc.enable_card_emulation_euicc") public static final int SET_SUBSCRIPTION_ID_STATUS_SUCCESS = 0; // 0x0
   }
 
 }
diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl
index a08b55f..ac0a5aa 100644
--- a/nfc/java/android/nfc/INfcAdapter.aidl
+++ b/nfc/java/android/nfc/INfcAdapter.aidl
@@ -31,6 +31,7 @@
 import android.nfc.INfcFCardEmulation;
 import android.nfc.INfcOemExtensionCallback;
 import android.nfc.INfcUnlockHandler;
+import android.nfc.IT4tNdefNfcee;
 import android.nfc.ITagRemovedCallback;
 import android.nfc.INfcDta;
 import android.nfc.INfcWlcStateListener;
@@ -52,8 +53,8 @@
     int getState();
     boolean disable(boolean saveState, in String pkg);
     boolean enable(in String pkg);
-    void pausePolling(int timeoutInMs);
-    void resumePolling();
+    int pausePolling(long timeoutInMs);
+    int resumePolling();
 
     void setForegroundDispatch(in PendingIntent intent,
             in IntentFilter[] filters, in TechListParcel techLists);
@@ -114,7 +115,7 @@
     void clearPreference();
     void setScreenState();
     void checkFirmware();
-    List<String> fetchActiveNfceeList();
+    Map fetchActiveNfceeList();
     void triggerInitialization();
     boolean getSettingStatus();
     boolean isTagPresent();
@@ -122,4 +123,6 @@
     void indicateDataMigration(boolean inProgress, String pkg);
     int commitRouting();
     boolean isTagIntentAllowed(in String pkg, in int Userid);
+    IT4tNdefNfcee getT4tNdefNfceeInterface();
+    long getMaxPausePollingTimeoutMs();
 }
diff --git a/nfc/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl
index 633d8bf..bb9fe95 100644
--- a/nfc/java/android/nfc/INfcCardEmulation.aidl
+++ b/nfc/java/android/nfc/INfcCardEmulation.aidl
@@ -53,6 +53,8 @@
     void overrideRoutingTable(int userHandle, String protocol, String technology, in String pkg);
     void recoverRoutingTable(int userHandle);
     boolean isEuiccSupported();
+    int getDefaultNfcSubscriptionId(in String pkg);
+    int setDefaultNfcSubscriptionId(int subscriptionId, in String pkg);
     void setAutoChangeStatus(boolean state);
     boolean isAutoChangeEnabled();
     List<String> getRoutingStatus();
diff --git a/nfc/java/android/nfc/IT4tNdefNfcee.aidl b/nfc/java/android/nfc/IT4tNdefNfcee.aidl
new file mode 100644
index 0000000..b4cda5b
--- /dev/null
+++ b/nfc/java/android/nfc/IT4tNdefNfcee.aidl
@@ -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 android.nfc;
+
+import android.nfc.T4tNdefNfceeCcFileInfo;
+
+/**
+ * @hide
+ */
+interface IT4tNdefNfcee {
+    int writeData(in int fileId, in byte[] data);
+    byte[] readData(in int fileId);
+    int clearNdefData();
+    boolean isNdefOperationOngoing();
+    boolean isNdefNfceeEmulationSupported();
+    T4tNdefNfceeCcFileInfo readCcfile();
+}
diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index 056844f..89ce423 100644
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -589,6 +589,7 @@
     static INfcTag sTagService;
     static INfcCardEmulation sCardEmulationService;
     static INfcFCardEmulation sNfcFCardEmulationService;
+    static IT4tNdefNfcee sNdefNfceeService;
 
     /**
      * The NfcAdapter object for each application context.
@@ -827,7 +828,13 @@
                     throw new UnsupportedOperationException();
                 }
             }
-
+            try {
+                sNdefNfceeService = sService.getT4tNdefNfceeInterface();
+            } catch (RemoteException e) {
+                sNdefNfceeService = null;
+                Log.e(TAG, "could not retrieve NDEF NFCEE service");
+                throw new UnsupportedOperationException();
+            }
             sIsInitialized = true;
         }
         NfcAdapter adapter = sNfcAdapters.get(context);
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
index 9ed678f..f78161e 100644
--- a/nfc/java/android/nfc/NfcOemExtension.java
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -39,6 +39,7 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
+import android.se.omapi.Reader;
 import android.util.Log;
 
 import java.lang.annotation.Retention;
@@ -148,6 +149,48 @@
     public @interface ControllerMode{}
 
     /**
+     * Technology Type for {@link #getActiveNfceeList()}.
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    public static final int NFCEE_TECH_NONE = 0;
+
+    /**
+     * Technology Type for {@link #getActiveNfceeList()}.
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    public static final int NFCEE_TECH_A = 1;
+
+    /**
+     * Technology Type for {@link #getActiveNfceeList()}.
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    public static final int NFCEE_TECH_B = 1 << 1;
+
+    /**
+     * Technology Type for {@link #getActiveNfceeList()}.
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    public static final int NFCEE_TECH_F = 1 << 2;
+
+    /**
+     * Nfc technology flags for {@link #getActiveNfceeList()}.
+     *
+     * @hide
+     */
+    @IntDef(flag = true, value = {
+        NFCEE_TECH_NONE,
+        NFCEE_TECH_A,
+        NFCEE_TECH_B,
+        NFCEE_TECH_F,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface NfceeTechnology {}
+
+    /**
      * Event that Host Card Emulation is activated.
      */
     public static final int HCE_ACTIVATE = 1;
@@ -173,6 +216,31 @@
     public @interface HostCardEmulationAction {}
 
     /**
+     * Status code returned when the polling state change request succeeded.
+     * @see #pausePolling()
+     * @see #resumePolling()
+     */
+    public static final int POLLING_STATE_CHANGE_SUCCEEDED = 1;
+    /**
+     * Status code returned when the polling state change request is already in
+     * required state.
+     * @see #pausePolling()
+     * @see #resumePolling()
+     */
+    public static final int POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE = 2;
+    /**
+     * Possible status codes for {@link #pausePolling()} and
+     * {@link #resumePolling()}.
+     * @hide
+     */
+    @IntDef(value = {
+            POLLING_STATE_CHANGE_SUCCEEDED,
+            POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PollingStateChangeStatusCode {}
+
+    /**
      * Status OK
      */
     public static final int STATUS_OK = 0;
@@ -467,6 +535,28 @@
     }
 
     /**
+     * Get an instance of {@link T4tNdefNfcee} object for performing T4T (Type-4 Tag)
+     * NDEF (NFC Data Exchange Format) NFCEE (NFC Execution Environment) operations.
+     * This can be used to write NDEF data to emulate a T4T tag in an NFCEE
+     * (NFC Execution Environment - eSE, SIM, etc). Refer to the NFC forum specification
+     * "NFCForum-TS-NCI-2.3 section 10.4" and "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+     *
+     * This is a singleton object which shall be used by OEM extension module to do NDEF-NFCEE
+     * read/write operations.
+     *
+     * <p>Returns {@link T4tNdefNfcee}
+     * <p>Does not cause any RF activity and does not block.
+     * @return NFC Data Exchange Format (NDEF) NFC Execution Environment (NFCEE) object
+     * @hide
+     */
+    @SystemApi
+    @NonNull
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    public T4tNdefNfcee getT4tNdefNfcee() {
+        return T4tNdefNfcee.getInstance();
+    }
+
+    /**
      * Register an {@link Callback} to listen for NFC oem extension callbacks
      * Multiple clients can register and callbacks will be invoked asynchronously.
      *
@@ -580,14 +670,18 @@
     /**
      * Get the Active NFCEE (NFC Execution Environment) List
      *
-     * @return List of activated secure elements on success
-     *         which can contain "eSE" and "UICC", otherwise empty list.
+     * @see Reader#getName() for the list of possible NFCEE names.
+     *
+     * @return Map< String, @NfceeTechnology Integer >
+     *         A HashMap where keys are activated secure elements and
+     *         the values are bitmap of technologies supported by each secure element
+     *         on success keys can contain "eSE" and "UICC", otherwise empty map.
      */
     @NonNull
     @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
-    public List<String> getActiveNfceeList() {
+    public Map<String, Integer> getActiveNfceeList() {
         return NfcAdapter.callServiceReturn(() ->
-            NfcAdapter.sService.fetchActiveNfceeList(), new ArrayList<String>());
+            NfcAdapter.sService.fetchActiveNfceeList(), new HashMap<String, Integer>());
     }
 
     /**
@@ -653,24 +747,45 @@
 
     /**
      * Pauses NFC tag reader mode polling for a {@code timeoutInMs} millisecond.
-     * In case of {@code timeoutInMs} is zero or invalid polling will be stopped indefinitely
-     * use {@link #resumePolling()} to resume the polling.
-     * @param timeoutInMs the pause polling duration in millisecond, ranging from 0 to 40000.
+     * In case of {@code timeoutInMs} is zero or invalid polling will be stopped indefinitely.
+     * Use {@link #resumePolling()} to resume the polling.
+     * Use {@link #getMaxPausePollingTimeoutMs()} to check the max timeout value.
+     * @param timeoutInMs the pause polling duration in millisecond.
+     * @return status of the operation
+     * @throws IllegalArgumentException if timeoutInMs value is invalid
+     *         (0 < timeoutInMs < max).
      */
     @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
-    public void pausePolling(@DurationMillisLong int timeoutInMs) {
-        NfcAdapter.callService(() -> NfcAdapter.sService.pausePolling(timeoutInMs));
+    public @PollingStateChangeStatusCode int pausePolling(@DurationMillisLong long timeoutInMs) {
+        return NfcAdapter.callServiceReturn(() ->
+                NfcAdapter.sService.pausePolling(timeoutInMs),
+                POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE);
     }
 
     /**
      * Resumes default NFC tag reader mode polling for the current device state if polling is
      * paused. Calling this while already in polling is a no-op.
+     * @return status of the operation
      */
     @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
-    public void resumePolling() {
-        NfcAdapter.callService(() -> NfcAdapter.sService.resumePolling());
+    public @PollingStateChangeStatusCode int resumePolling() {
+        return NfcAdapter.callServiceReturn(() ->
+                NfcAdapter.sService.resumePolling(),
+                POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE);
+    }
+
+    /**
+     * Gets the max pause polling timeout value in millisecond.
+     * @return long integer representing the max timeout
+     */
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    @DurationMillisLong
+    public long getMaxPausePollingTimeoutMills() {
+        return NfcAdapter.callServiceReturn(() ->
+                NfcAdapter.sService.getMaxPausePollingTimeoutMs(), 0L);
     }
 
     /**
diff --git a/nfc/java/android/nfc/NfcRoutingTableEntry.java b/nfc/java/android/nfc/NfcRoutingTableEntry.java
index 4e91377..c2cbbed 100644
--- a/nfc/java/android/nfc/NfcRoutingTableEntry.java
+++ b/nfc/java/android/nfc/NfcRoutingTableEntry.java
@@ -17,8 +17,12 @@
 
 
 import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
 import android.annotation.SystemApi;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Class to represent an entry of routing table. This class is abstract and extended by
  * {@link RoutingTableTechnologyEntry}, {@link RoutingTableProtocolEntry},
@@ -30,10 +34,42 @@
 @SystemApi
 public abstract class NfcRoutingTableEntry {
     private final int mNfceeId;
+    private final int mType;
+
+    /**
+     * AID routing table type.
+     */
+    public static final int TYPE_AID = 0;
+    /**
+     * Protocol routing table type.
+     */
+    public static final int TYPE_PROTOCOL = 1;
+    /**
+     * Technology routing table type.
+     */
+    public static final int TYPE_TECHNOLOGY = 2;
+    /**
+     * System Code routing table type.
+     */
+    public static final int TYPE_SYSTEM_CODE = 3;
+
+    /**
+     * Possible type of this routing table entry.
+     * @hide
+     */
+    @IntDef(prefix = "TYPE_", value = {
+            TYPE_AID,
+            TYPE_PROTOCOL,
+            TYPE_TECHNOLOGY,
+            TYPE_SYSTEM_CODE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RoutingTableType {}
 
     /** @hide */
-    protected NfcRoutingTableEntry(int nfceeId) {
+    protected NfcRoutingTableEntry(int nfceeId, @RoutingTableType int type) {
         mNfceeId = nfceeId;
+        mType = type;
     }
 
     /**
@@ -43,4 +79,13 @@
     public int getNfceeId() {
         return mNfceeId;
     }
+
+    /**
+     * Get the type of this entry.
+     * @return an integer defined in {@link RoutingTableType}
+     */
+    @RoutingTableType
+    public int getType() {
+        return mType;
+    }
 }
diff --git a/nfc/java/android/nfc/RoutingTableAidEntry.java b/nfc/java/android/nfc/RoutingTableAidEntry.java
index 7634fe3..bf697d6 100644
--- a/nfc/java/android/nfc/RoutingTableAidEntry.java
+++ b/nfc/java/android/nfc/RoutingTableAidEntry.java
@@ -20,7 +20,7 @@
 import android.annotation.SystemApi;
 
 /**
- * Represents an AID entry in current routing table.
+ * Represents an Application ID (AID) entry in current routing table.
  * @hide
  */
 @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
@@ -30,7 +30,7 @@
 
     /** @hide */
     public RoutingTableAidEntry(int nfceeId, String value) {
-        super(nfceeId);
+        super(nfceeId, TYPE_AID);
         this.mValue = value;
     }
 
diff --git a/nfc/java/android/nfc/RoutingTableProtocolEntry.java b/nfc/java/android/nfc/RoutingTableProtocolEntry.java
index 0c5be7d..536de4d 100644
--- a/nfc/java/android/nfc/RoutingTableProtocolEntry.java
+++ b/nfc/java/android/nfc/RoutingTableProtocolEntry.java
@@ -97,7 +97,7 @@
 
     /** @hide */
     public RoutingTableProtocolEntry(int nfceeId, @ProtocolValue int value) {
-        super(nfceeId);
+        super(nfceeId, TYPE_PROTOCOL);
         this.mValue = value;
     }
 
diff --git a/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java b/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java
index f87ad5f..f61892d 100644
--- a/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java
+++ b/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java
@@ -20,7 +20,9 @@
 import android.annotation.SystemApi;
 
 /**
- * Represents a system code entry in current routing table.
+ * Represents a system code entry in current routing table, where system codes are two-byte values
+ * used in NFC-F technology (a type of NFC communication) to identify specific
+ * device configurations.
  * @hide
  */
 @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
@@ -30,7 +32,7 @@
 
     /** @hide */
     public RoutingTableSystemCodeEntry(int nfceeId, byte[] value) {
-        super(nfceeId);
+        super(nfceeId, TYPE_SYSTEM_CODE);
         this.mValue = value;
     }
 
diff --git a/nfc/java/android/nfc/RoutingTableTechnologyEntry.java b/nfc/java/android/nfc/RoutingTableTechnologyEntry.java
index f51a529..2dbc942 100644
--- a/nfc/java/android/nfc/RoutingTableTechnologyEntry.java
+++ b/nfc/java/android/nfc/RoutingTableTechnologyEntry.java
@@ -30,22 +30,27 @@
 @SystemApi
 public class RoutingTableTechnologyEntry extends NfcRoutingTableEntry {
     /**
-     * Technology-A
+     * Technology-A.
+     * <p>Tech-A is mostly used for payment and ticketing applications. It supports various
+     * Tag platforms including Type 1, Type 2 and Type 4A tags. </p>
      */
     @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
     public static final int TECHNOLOGY_A = 0;
     /**
-     * Technology-B
+     * Technology-B which is based on ISO/IEC 14443-3 standard.
      */
     @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
     public static final int TECHNOLOGY_B = 1;
     /**
-     * Technology-F
+     * Technology-F.
+     * <p>Tech-F is a standard which supports Type 3 Tags and NFC-DEP protocol etc.</p>
      */
     @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
     public static final int TECHNOLOGY_F = 2;
     /**
-     * Technology-V
+     * Technology-V.
+     * <p>Tech-V is an NFC technology used for communication with passive tags that operate
+     * at a longer range than other NFC technologies. </p>
      */
     @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
     public static final int TECHNOLOGY_V = 3;
@@ -73,7 +78,7 @@
 
     /** @hide */
     public RoutingTableTechnologyEntry(int nfceeId, @TechnologyValue int value) {
-        super(nfceeId);
+        super(nfceeId, TYPE_TECHNOLOGY);
         this.mValue = value;
     }
 
diff --git a/nfc/java/android/nfc/T4tNdefNfcee.java b/nfc/java/android/nfc/T4tNdefNfcee.java
new file mode 100644
index 0000000..06d02c5
--- /dev/null
+++ b/nfc/java/android/nfc/T4tNdefNfcee.java
@@ -0,0 +1,258 @@
+/*
+ * 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.nfc;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.WorkerThread;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This class is used for performing T4T (Type-4 Tag) NDEF (NFC Data Exchange Format)
+ * NFCEE (NFC Execution Environment) operations.
+ * This can be used to write NDEF data to emulate a T4T tag in an NFCEE
+ * (NFC Execution Environment - eSE, SIM, etc). Refer to the NFC forum specification
+ * "NFCForum-TS-NCI-2.3 section 10.4" and "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+@SystemApi
+public final class T4tNdefNfcee {
+    private static final String TAG = "NdefNfcee";
+    static T4tNdefNfcee sNdefNfcee;
+
+    private T4tNdefNfcee() {
+    }
+
+    /**
+     * Helper to get an instance of this class.
+     *
+     * @return
+     * @hide
+     */
+    @NonNull
+    public static T4tNdefNfcee getInstance() {
+        if (sNdefNfcee == null) {
+            sNdefNfcee = new T4tNdefNfcee();
+        }
+        return sNdefNfcee;
+    }
+
+    /**
+     * Return flag for {@link #writeData(int, byte[])}.
+     * It indicates write data is successful.
+     */
+    public static final int WRITE_DATA_SUCCESS = 0;
+    /**
+     * Return flag for {@link #writeData(int, byte[])}.
+     * It indicates write data fail due to unknown reasons.
+     */
+    public static final int WRITE_DATA_ERROR_INTERNAL = -1;
+    /**
+     * Return flag for {@link #writeData(int, byte[])}.
+     * It indicates write data fail due to ongoing rf activity.
+     */
+    public static final int WRITE_DATA_ERROR_RF_ACTIVATED = -2;
+    /**
+     * Return flag for {@link #writeData(int, byte[])}.
+     * It indicates write data fail due to Nfc off.
+     */
+    public static final int WRITE_DATA_ERROR_NFC_NOT_ON = -3;
+    /**
+     * Return flag for {@link #writeData(int, byte[])}.
+     * It indicates write data fail due to invalid file id.
+     */
+    public static final int WRITE_DATA_ERROR_INVALID_FILE_ID = -4;
+    /**
+     * Return flag for {@link #writeData(int, byte[])}.
+     * It indicates write data fail due to invalid length.
+     */
+    public static final int WRITE_DATA_ERROR_INVALID_LENGTH = -5;
+    /**
+     * Return flag for {@link #writeData(int, byte[])}.
+     * It indicates write data fail due to core connection create failure.
+     */
+    public static final int WRITE_DATA_ERROR_CONNECTION_FAILED = -6;
+    /**
+     * Return flag for {@link #writeData(int, byte[])}.
+     * It indicates write data fail due to empty payload.
+     */
+    public static final int WRITE_DATA_ERROR_EMPTY_PAYLOAD = -7;
+    /**
+     * Returns flag for {@link #writeData(int, byte[])}.
+     * It idicates write data fail due to invalid ndef format.
+     */
+    public static final int WRITE_DATA_ERROR_NDEF_VALIDATION_FAILED = -8;
+
+    /**
+     * Possible return values for {@link #writeData(int, byte[])}.
+     *
+     * @hide
+     */
+    @IntDef(prefix = { "WRITE_DATA_" }, value = {
+        WRITE_DATA_SUCCESS,
+        WRITE_DATA_ERROR_INTERNAL,
+        WRITE_DATA_ERROR_RF_ACTIVATED,
+        WRITE_DATA_ERROR_NFC_NOT_ON,
+        WRITE_DATA_ERROR_INVALID_FILE_ID,
+        WRITE_DATA_ERROR_INVALID_LENGTH,
+        WRITE_DATA_ERROR_CONNECTION_FAILED,
+        WRITE_DATA_ERROR_EMPTY_PAYLOAD,
+        WRITE_DATA_ERROR_NDEF_VALIDATION_FAILED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface WriteDataStatus{}
+
+    /**
+     * This API performs writes of T4T data to NFCEE.
+     *
+     * <p>This is an I/O operation and will block until complete. It must
+     * not be called from the main application thread.</p>
+     *
+     * @param fileId File id (Refer NFC Forum Type 4 Tag Specification
+     *               Section 4.2 File Identifiers and Access Conditions
+     *               for more information) to which to write.
+     * @param data   This should be valid Ndef Message format.
+     *               Refer to Nfc forum NDEF specification NDEF Message section
+     * @return status of the operation.
+     * @hide
+     */
+    @SystemApi
+    @WorkerThread
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public @WriteDataStatus int writeData(@IntRange(from = 0, to = 65535) int fileId,
+            @NonNull byte[] data) {
+        return NfcAdapter.callServiceReturn(() ->
+                NfcAdapter.sNdefNfceeService.writeData(fileId, data), WRITE_DATA_ERROR_INTERNAL);
+    }
+
+    /**
+     * This API performs reading of T4T content of Nfcee.
+     *
+     * <p>This is an I/O operation and will block until complete. It must
+     * not be called from the main application thread.</p>
+     *
+     * @param fileId File Id (Refer
+     *               Section 4.2 File Identifiers and Access Conditions
+     *               for more information) from which to read.
+     * @return - Returns Ndef message if success
+     *           Refer to Nfc forum NDEF specification NDEF Message section
+     * @throws IllegalStateException if read fails because the fileId is invalid.
+     * @hide
+     */
+    @SystemApi
+    @WorkerThread
+    @NonNull
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public byte[] readData(@IntRange(from = 0, to = 65535) int fileId) {
+        return NfcAdapter.callServiceReturn(() ->
+            NfcAdapter.sNdefNfceeService.readData(fileId), null);
+    }
+
+    /**
+     * Return flag for {@link #clearNdefData()}.
+     * It indicates clear data is successful.
+     */
+    public static final int CLEAR_DATA_SUCCESS = 1;
+     /**
+     * Return flag for {@link #clearNdefData()}.
+     * It indicates clear data failed due to internal error while processing the clear.
+     */
+    public static final int CLEAR_DATA_FAILED_INTERNAL = 0;
+
+    /**
+     * Possible return values for {@link #clearNdefData()}.
+     *
+     * @hide
+     */
+    @IntDef(prefix = { "CLEAR_DATA_" }, value = {
+        CLEAR_DATA_SUCCESS,
+        CLEAR_DATA_FAILED_INTERNAL,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ClearDataStatus{}
+
+    /**
+     * This API will set all the T4T NDEF NFCEE data to zero.
+     *
+     * <p>This is an I/O operation and will block until complete. It must
+     * not be called from the main application thread.
+     *
+     * <p>This API can be called regardless of NDEF file lock state.
+     * </p>
+     * @return status of the operation
+     *
+     * @hide
+     */
+    @SystemApi
+    @WorkerThread
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public @ClearDataStatus int clearData() {
+        return NfcAdapter.callServiceReturn(() ->
+            NfcAdapter.sNdefNfceeService.clearNdefData(), CLEAR_DATA_FAILED_INTERNAL);
+    }
+
+    /**
+     * Returns whether NDEF NFCEE operation is ongoing or not.
+     *
+     * @return true if NDEF NFCEE operation is ongoing, else false.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public boolean isOperationOngoing() {
+        return NfcAdapter.callServiceReturn(() ->
+            NfcAdapter.sNdefNfceeService.isNdefOperationOngoing(), false);
+    }
+
+    /**
+     * This Api is to check the status of NDEF NFCEE emulation feature is
+     * supported or not.
+     *
+     * @return true if NDEF NFCEE emulation feature is supported, else false.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public boolean isSupported() {
+        return NfcAdapter.callServiceReturn(() ->
+            NfcAdapter.sNdefNfceeService.isNdefNfceeEmulationSupported(), false);
+    }
+
+    /**
+     * This API performs reading of T4T NDEF NFCEE CC file content.
+     *
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" for more details.
+     *
+     * @return Returns CC file content if success or null if failed to read.
+     * @hide
+     */
+    @SystemApi
+    @WorkerThread
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    @Nullable
+    public T4tNdefNfceeCcFileInfo readCcfile() {
+        return NfcAdapter.callServiceReturn(() ->
+            NfcAdapter.sNdefNfceeService.readCcfile(), null);
+    }
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.aidl
similarity index 73%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.aidl
index 7d3d8b9..f72f74e 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.aidl
@@ -13,10 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
-}
+package android.nfc;
+
+parcelable T4tNdefNfceeCcFileInfo;
+
diff --git a/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.java b/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.java
new file mode 100644
index 0000000..5fca052
--- /dev/null
+++ b/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.java
@@ -0,0 +1,293 @@
+/*
+ * 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.nfc;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This class is used to represence T4T (Type-4 Tag) NDEF (NFC Data Exchange Format)
+ * NFCEE (NFC Execution Environment) CC (Capability Container) File data.
+ * The CC file stores metadata about the T4T tag being emulated.
+ *
+ * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" for more details.
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+@SystemApi
+public final class T4tNdefNfceeCcFileInfo implements Parcelable {
+    /**
+     * Indicates the size of this capability container (called “CC File”)<p>
+     */
+    private int mCcLength;
+    /**
+     * Indicates the mapping specification version<p>
+     */
+    private int mVersion;
+    /**
+     * Indicates the max data size by a single ReadBinary<p>
+     */
+    private int mMaxReadLength;
+    /**
+     * Indicates the max data size by a single UpdateBinary<p>
+     */
+    private int mMaxWriteLength;
+    /**
+     * Indicates the NDEF File Identifier<p>
+     */
+    private int mFileId;
+    /**
+     * Indicates the maximum Max NDEF file size<p>
+     */
+    private int mMaxSize;
+    /**
+     * Indicates the read access condition<p>
+     */
+    private int mReadAccess;
+    /**
+     * Indicates the write access condition<p>
+     */
+    private int mWriteAccess;
+
+    /**
+     * Constructor to be used by NFC service and internal classes.
+     * @hide
+     */
+    public T4tNdefNfceeCcFileInfo(int cclen, int version, int maxLe, int maxLc,
+                      int ndefFileId, int ndefMaxSize,
+                      int ndefReadAccess, int ndefWriteAccess) {
+        mCcLength = cclen;
+        mVersion = version;
+        mMaxWriteLength = maxLc;
+        mMaxReadLength = maxLe;
+        mFileId = ndefFileId;
+        mMaxSize = ndefMaxSize;
+        mReadAccess = ndefReadAccess;
+        mWriteAccess = ndefWriteAccess;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+
+        dest.writeInt(mCcLength);
+        dest.writeInt(mVersion);
+        dest.writeInt(mMaxWriteLength);
+        dest.writeInt(mMaxReadLength);
+        dest.writeInt(mFileId);
+        dest.writeInt(mMaxSize);
+        dest.writeInt(mReadAccess);
+        dest.writeInt(mWriteAccess);
+    }
+
+    /**
+     * Indicates the size of this capability container (called “CC File”).
+     *
+     * @return length of the CC file.
+     */
+    @IntRange(from = 0xf, to = 0x7fff)
+    public int getCcFileLength() {
+        return mCcLength;
+    }
+
+    /**
+     * T4T tag mapping version 2.0.
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" for more details.
+     */
+    public static final int VERSION_2_0 = 0x20;
+    /**
+     * T4T tag mapping version 2.0.
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" for more details.
+     */
+    public static final int VERSION_3_0 = 0x30;
+
+    /**
+     * Possible return values for {@link #getVersion()}.
+     * @hide
+     */
+    @IntDef(prefix = { "VERSION_" }, value = {
+            VERSION_2_0,
+            VERSION_3_0,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Version{}
+
+    /**
+     * Indicates the mapping version of the T4T tag supported.
+     *
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.5" for more details.
+     *
+     * @return version of the specification
+     */
+    @Version
+    public int getVersion() {
+        return mVersion;
+    }
+
+    /**
+     * Indicates the max data size that can be read by a single invocation of
+     * {@link T4tNdefNfcee#readData(int)}.
+     *
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" MLe.
+     * @return max size of read (in bytes).
+     */
+    @IntRange(from = 0xf, to = 0xffff)
+    public int getMaxReadLength() {
+        return mMaxReadLength;
+    }
+
+    /**
+     * Indicates the max data size that can be written by a single invocation of
+     * {@link T4tNdefNfcee#writeData(int, byte[])}
+     *
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" MLc.
+     * @return max size of write (in bytes).
+     */
+    @IntRange(from = 0xd, to = 0xffff)
+    public int getMaxWriteLength() {
+        return mMaxWriteLength;
+    }
+
+    /**
+     * Indicates the NDEF File Identifier. This is the identifier used in the last invocation of
+     * {@link T4tNdefNfcee#writeData(int, byte[])}
+     *
+     * @return FileId of the data stored or -1 if no data is present.
+     */
+    @IntRange(from = -1, to = 65535)
+    public int getFileId() {
+        return mFileId;
+    }
+
+    /**
+     * Indicates the maximum size of T4T NDEF data that can be written to the NFCEE.
+     *
+     * @return max size of the contents.
+     */
+    @IntRange(from = 0x5, to = 0x7fff)
+    public int getMaxSize() {
+        return mMaxSize;
+    }
+
+    /**
+     * T4T tag read access granted without any security.
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+     */
+    public static final int READ_ACCESS_GRANTED_UNRESTRICTED = 0x0;
+    /**
+     * T4T tag read access granted with limited proprietary access only.
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+     */
+    public static final int READ_ACCESS_GRANTED_RESTRICTED = 0x80;
+
+    /**
+     * Possible return values for {@link #getVersion()}.
+     * @hide
+     */
+    @IntDef(prefix = { "READ_ACCESS_GRANTED_" }, value = {
+            READ_ACCESS_GRANTED_RESTRICTED,
+            READ_ACCESS_GRANTED_UNRESTRICTED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ReadAccess {}
+
+    /**
+     * Indicates the read access condition.
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+     * @return read access restriction
+     */
+    @ReadAccess
+    public int getReadAccess() {
+        return mReadAccess;
+    }
+
+    /**
+     * T4T tag write access granted without any security.
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+     */
+    public static final int WRITE_ACCESS_GRANTED_UNRESTRICTED = 0x0;
+    /**
+     * T4T tag write access granted with limited proprietary access only.
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+     */
+    public static final int WRITE_ACCESS_GRANTED_RESTRICTED = 0x80;
+    /**
+     * T4T tag write access not granted.
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+     */
+    public static final int WRITE_ACCESS_NOT_GRANTED = 0xFF;
+
+    /**
+     * Possible return values for {@link #getVersion()}.
+     * @hide
+     */
+    @IntDef(prefix = { "READ_ACCESS_GRANTED_" }, value = {
+            WRITE_ACCESS_GRANTED_RESTRICTED,
+            WRITE_ACCESS_GRANTED_UNRESTRICTED,
+            WRITE_ACCESS_NOT_GRANTED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface WriteAccess {}
+
+    /**
+     * Indicates the write access condition.
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+     * @return write access restriction
+     */
+    @WriteAccess
+    public int getWriteAccess() {
+        return mWriteAccess;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final @NonNull Parcelable.Creator<T4tNdefNfceeCcFileInfo> CREATOR =
+            new Parcelable.Creator<>() {
+                @Override
+                public T4tNdefNfceeCcFileInfo createFromParcel(Parcel in) {
+
+                    // NdefNfceeCcFileInfo fields
+                    int cclen = in.readInt();
+                    int version = in.readInt();
+                    int maxLe = in.readInt();
+                    int maxLc = in.readInt();
+                    int ndefFileId = in.readInt();
+                    int ndefMaxSize = in.readInt();
+                    int ndefReadAccess = in.readInt();
+                    int ndefWriteAccess = in.readInt();
+
+                    return new T4tNdefNfceeCcFileInfo(cclen, version, maxLe, maxLc,
+                            ndefFileId, ndefMaxSize,
+                            ndefReadAccess, ndefWriteAccess);
+                }
+
+                @Override
+                public T4tNdefNfceeCcFileInfo[] newArray(int size) {
+                    return new T4tNdefNfceeCcFileInfo[size];
+                }
+            };
+}
diff --git a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
index 9ff83fe..308b5d1 100644
--- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -171,6 +171,12 @@
     private boolean mShouldDefaultToObserveMode;
 
     /**
+     * Whether or not this service wants to share the same routing priority as the
+     * Wallet role owner.
+     */
+    private boolean mShareRolePriority;
+
+    /**
      * @hide
      */
     @UnsupportedAppUsage
@@ -307,6 +313,12 @@
                 mShouldDefaultToObserveMode = sa.getBoolean(
                         R.styleable.HostApduService_shouldDefaultToObserveMode,
                         false);
+                if (Flags.nfcAssociatedRoleServices()) {
+                    mShareRolePriority = sa.getBoolean(
+                            R.styleable.HostApduService_shareRolePriority,
+                            false
+                    );
+                }
                 sa.recycle();
             } else {
                 TypedArray sa = res.obtainAttributes(attrs,
@@ -337,6 +349,12 @@
                     }
                 }
                 mStaticOffHostName = mOffHostName;
+                if (Flags.nfcAssociatedRoleServices()) {
+                    mShareRolePriority = sa.getBoolean(
+                            R.styleable.OffHostApduService_shareRolePriority,
+                            false
+                    );
+                }
                 sa.recycle();
             }
 
@@ -728,6 +746,17 @@
     }
 
     /**
+     * Returns whether or not this service wants to share the Wallet role holder priority
+     * with other packages/services with the same signature.
+     *
+     * @return whether or not this service wants to share priority
+     */
+    @FlaggedApi(Flags.FLAG_NFC_ASSOCIATED_ROLE_SERVICES)
+    public boolean shareRolePriority() {
+        return mShareRolePriority;
+    }
+
+    /**
      * Returns description of service.
      * @return user readable description of service
      */
diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
index 24ff7ab..8037702 100644
--- a/nfc/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
@@ -22,6 +22,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -45,6 +46,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
+import android.telephony.SubscriptionManager;
 import android.util.ArrayMap;
 import android.util.Log;
 
@@ -244,6 +246,25 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface SetServiceEnabledStatusCode {}
 
+    /**
+     * Property name used to indicate that an application wants to allow associated services
+     * to share the same AID routing priority when this application is the role holder.
+     * <p>
+     * Example:
+     * <pre>
+     *     {@code
+     *     <application>
+     *       ...
+     *       <property android:name="android.nfc.cardemulation.PROPERTY_ALLOW_SHARED_ROLE_PRIORITY"
+     *         android:value="true"/>
+     *     </application>
+     *     }
+     * </pre>
+     */
+    @FlaggedApi(Flags.FLAG_NFC_ASSOCIATED_ROLE_SERVICES)
+    public static final String PROPERTY_ALLOW_SHARED_ROLE_PRIORITY =
+            "android.nfc.cardemulation.PROPERTY_ALLOW_SHARED_ROLE_PRIORITY";
+
     static boolean sIsInitialized = false;
     static HashMap<Context, CardEmulation> sCardEmus = new HashMap<Context, CardEmulation>();
     static INfcCardEmulation sService;
@@ -1010,6 +1031,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
     @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE)
     public void overrideRoutingTable(
             @NonNull Activity activity, @ProtocolAndTechnologyRoute int protocol,
@@ -1037,6 +1059,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
     @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE)
     public void recoverRoutingTable(@NonNull Activity activity) {
         if (!activity.isResumed()) {
@@ -1058,6 +1081,97 @@
     }
 
     /**
+     * Setting the default subscription ID succeeded.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
+    public static final int SET_SUBSCRIPTION_ID_STATUS_SUCCESS = 0;
+
+    /**
+     * Setting the default subscription ID failed because the subscription ID is invalid.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
+    public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_INVALID_SUBSCRIPTION_ID = 1;
+
+    /**
+     * Setting the default subscription ID failed because there was an internal error processing
+     * the request. For ex: NFC service died in the middle of handling the API.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
+    public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_INTERNAL_ERROR = 2;
+
+    /**
+     * Setting the default subscription ID failed because this feature is not supported on the
+     * device.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
+    public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_NOT_SUPPORTED = 3;
+
+    /** @hide */
+    @IntDef(prefix = "SET_SUBSCRIPTION_ID_STATUS_",
+            value = {
+                    SET_SUBSCRIPTION_ID_STATUS_SUCCESS,
+                    SET_SUBSCRIPTION_ID_STATUS_FAILED_INVALID_SUBSCRIPTION_ID,
+                    SET_SUBSCRIPTION_ID_STATUS_FAILED_INTERNAL_ERROR,
+                    SET_SUBSCRIPTION_ID_STATUS_FAILED_NOT_SUPPORTED,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SetSubscriptionIdStatus {}
+
+    /**
+     * Sets the system's default NFC subscription id.
+     *
+     * <p> For devices with multiple UICC/EUICC that is configured to be NFCEE, this sets the
+     * default UICC NFCEE that will handle NFC offhost CE transactoions </p>
+     *
+     * @param subscriptionId the default NFC subscription Id to set.
+     * @return status of the operation.
+     *
+     * @throws UnsupportedOperationException If the device does not have
+     * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}.
+     * @hide
+     */
+    @SystemApi
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
+    public @SetSubscriptionIdStatus int setDefaultNfcSubscriptionId(int subscriptionId) {
+        return callServiceReturn(() ->
+                        sService.setDefaultNfcSubscriptionId(
+                                subscriptionId, mContext.getPackageName()),
+                SET_SUBSCRIPTION_ID_STATUS_FAILED_INTERNAL_ERROR);
+    }
+
+    /**
+     * Returns the system's default NFC subscription id.
+     *
+     * <p> For devices with multiple UICC/EUICC that is configured to be NFCEE, this returns the
+     * default UICC NFCEE that will handle NFC offhost CE transactoions </p>
+     * <p> If the device has no UICC that can serve as NFCEE, this will return
+     * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.</p>
+     *
+     * @return the default NFC subscription Id if set,
+     * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} otherwise.
+     *
+     * @throws UnsupportedOperationException If the device does not have
+     * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}.
+     */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
+    @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
+    public int getDefaultNfcSubscriptionId() {
+        return callServiceReturn(() ->
+                sService.getDefaultNfcSubscriptionId(mContext.getPackageName()),
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+    }
+
+    /**
      * Returns the value of {@link Settings.Secure#NFC_PAYMENT_DEFAULT_COMPONENT}.
      *
      * @param context A context
diff --git a/nfc/tests/src/android/nfc/NdefMessageTest.java b/nfc/tests/src/android/nfc/NdefMessageTest.java
new file mode 100644
index 0000000..9ca295d
--- /dev/null
+++ b/nfc/tests/src/android/nfc/NdefMessageTest.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 android.nfc;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class NdefMessageTest {
+    private NdefMessage mNdefMessage;
+    private NdefRecord mNdefRecord;
+
+    @Before
+    public void setUp() {
+        mNdefRecord = NdefRecord.createUri("http://www.example.com");
+        mNdefMessage = new NdefMessage(mNdefRecord);
+    }
+
+    @After
+    public void tearDown() {
+    }
+
+    @Test
+    public void testGetRecords() {
+        NdefRecord[] records = mNdefMessage.getRecords();
+        assertThat(records).isNotNull();
+        assertThat(records).hasLength(1);
+        assertThat(records[0]).isEqualTo(mNdefRecord);
+    }
+
+    @Test
+    public void testToByteArray() throws FormatException {
+        byte[] bytes = mNdefMessage.toByteArray();
+        assertThat(bytes).isNotNull();
+        assertThat(bytes.length).isGreaterThan(0);
+        NdefMessage ndefMessage = new NdefMessage(bytes);
+        assertThat(ndefMessage).isNotNull();
+    }
+}
diff --git a/packages/CrashRecovery/framework/Android.bp b/packages/CrashRecovery/framework/Android.bp
index 2beffda..43d8a62 100644
--- a/packages/CrashRecovery/framework/Android.bp
+++ b/packages/CrashRecovery/framework/Android.bp
@@ -14,6 +14,7 @@
     name: "framework-platformcrashrecovery",
     srcs: [":framework-crashrecovery-sources"],
     defaults: ["framework-non-updatable-unbundled-defaults"],
+    permitted_packages: ["android.service.watchdog"],
     aidl: {
         include_dirs: [
             "frameworks/base/core/java",
diff --git a/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
index 8c15b09..2ba93f1 100644
--- a/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
+++ b/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
@@ -456,7 +456,7 @@
      *
      * <p>This method could be called frequently if there is a severe problem on the device.
      */
-    public void onPackageFailure(@NonNull List<VersionedPackage> packages,
+    public void notifyPackageFailure(@NonNull List<VersionedPackage> packages,
             @FailureReasons int failureReason) {
         if (packages == null) {
             Slog.w(TAG, "Could not resolve a list of failing packages");
@@ -467,7 +467,7 @@
             if (Flags.recoverabilityDetection()) {
                 if (now >= mLastMitigation
                         && (now - mLastMitigation) < getMitigationWindowMs()) {
-                    Slog.i(TAG, "Skipping onPackageFailure mitigation");
+                    Slog.i(TAG, "Skipping notifyPackageFailure mitigation");
                     return;
                 }
             }
@@ -494,7 +494,7 @@
                             ObserverInternal observer = mAllObservers.valueAt(oIndex);
                             PackageHealthObserver registeredObserver = observer.registeredObserver;
                             if (registeredObserver != null
-                                    && observer.onPackageFailureLocked(
+                                    && observer.notifyPackageFailureLocked(
                                     versionedPackage.getPackageName())) {
                                 MonitoredPackage p = observer.getMonitoredPackage(
                                         versionedPackage.getPackageName());
@@ -693,7 +693,7 @@
         // Check if native watchdog reported a crash
         if ("1".equals(SystemProperties.get("sys.init.updatable_crashing"))) {
             // We rollback all available low impact rollbacks when crash is unattributable
-            onPackageFailure(Collections.EMPTY_LIST, FAILURE_REASON_NATIVE_CRASH);
+            notifyPackageFailure(Collections.EMPTY_LIST, FAILURE_REASON_NATIVE_CRASH);
             // we stop polling after an attempt to execute rollback, regardless of whether the
             // attempt succeeds or not
         } else {
@@ -731,6 +731,25 @@
     }
 
     /**
+     * The minimum value that can be returned by any observer.
+     * It represents that no mitigations were available.
+     */
+    public static final int LEAST_PACKAGE_HEALTH_OBSERVER_IMPACT =
+            PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+
+    /**
+     * The mitigation impact beyond which the user will start noticing the mitigations.
+     */
+    public static final int MEDIUM_USER_IMPACT_THRESHOLD =
+            PackageHealthObserverImpact.USER_IMPACT_LEVEL_20;
+
+    /**
+     * The mitigation impact beyond which the user impact is severely high.
+     */
+    public static final int HIGH_USER_IMPACT_THRESHOLD =
+            PackageHealthObserverImpact.USER_IMPACT_LEVEL_71;
+
+    /**
      * Possible severity values of the user impact of a
      * {@link PackageHealthObserver#onExecuteHealthCheckMitigation}.
      * @hide
@@ -773,6 +792,11 @@
         /**
          * Called when health check fails for the {@code versionedPackage}.
          *
+         * Note: if the returned user impact is higher than
+         * {@link #DEFAULT_HIGH_USER_IMPACT_THRESHOLD}, then
+         * {@link #onExecuteHealthCheckMitigation} would be called only in severe device conditions
+         * like boot-loop or network failure.
+         *
          * @param versionedPackage the package that is failing. This may be null if a native
          *                          service is crashing.
          * @param failureReason   the type of failure that is occurring.
@@ -780,8 +804,8 @@
          *                        (including this time).
          *
          *
-         * @return any one of {@link PackageHealthObserverImpact} to express the impact
-         * to the user on {@link #onExecuteHealthCheckMitigation}
+         * @return any value greater than {@link #LEAST_PACKAGE_HEALTH_OBSERVER_IMPACT} to express
+         * the impact of mitigation on the user in {@link #onExecuteHealthCheckMitigation}
          */
         @PackageHealthObserverImpact int onHealthCheckFailed(
                 @Nullable VersionedPackage versionedPackage,
@@ -790,9 +814,8 @@
 
         /**
          * This would be called after {@link #onHealthCheckFailed}.
-         * This is called only if current observer returned least
-         * {@link PackageHealthObserverImpact} mitigation for failed health
-         * check.
+         * This is called only if current observer returned least impact mitigation for failed
+         * health check.
          *
          * @param versionedPackage the package that is failing. This may be null if a native
          *                          service is crashing.
@@ -811,6 +834,9 @@
          *
          * @param mitigationCount the number of times mitigation has been attempted for this
          *                        boot loop (including this time).
+         *
+         * @return any value greater than {@link #LEAST_PACKAGE_HEALTH_OBSERVER_IMPACT} to express
+         * the impact of mitigation on the user in {@link #onExecuteBootLoopMitigation}
          */
         default @PackageHealthObserverImpact int onBootLoop(int mitigationCount) {
             return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
@@ -818,11 +844,13 @@
 
         /**
          * This would be called after {@link #onBootLoop}.
-         * This is called only if current observer returned least
-         * {@link PackageHealthObserverImpact} mitigation for fixing boot loop
+         * This is called only if current observer returned least impact mitigation for fixing
+         * boot loop.
          *
          * @param mitigationCount the number of times mitigation has been attempted for this
          *                        boot loop (including this time).
+         *
+         * @return {@code true} if action was executed successfully, {@code false} otherwise
          */
         default boolean onExecuteBootLoopMitigation(int mitigationCount) {
             return false;
@@ -916,7 +944,7 @@
      * effectively behave as if the explicit health check hasn't passed for {@code packageName}.
      *
      * <p> {@code packageName} can still be considered failed if reported by
-     * {@link #onPackageFailureLocked} before the package expires.
+     * {@link #notifyPackageFailureLocked} before the package expires.
      *
      * <p> Triggered by components outside the system server when they are fully functional after an
      * update.
@@ -1317,7 +1345,6 @@
      * Check if we're currently attempting to reboot during mitigation. This method must return
      * true if triggered reboot early during a boot loop, since the device will not be fully booted
      * at this time.
-     * @hide
      */
     public static boolean isRecoveryTriggeredReboot() {
         return isFactoryResetPropertySet() || isRebootPropertySet();
@@ -1461,7 +1488,7 @@
          * @hide
          */
         @GuardedBy("sLock")
-        public boolean onPackageFailureLocked(String packageName) {
+        public boolean notifyPackageFailureLocked(String packageName) {
             if (getMonitoredPackage(packageName) == null && registeredObserver.isPersistent()
                     && registeredObserver.mayObservePackage(packageName)) {
                 putMonitoredPackage(sPackageWatchdog.newMonitoredPackage(
diff --git a/packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java
index 129e47f..88fe36c 100644
--- a/packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java
+++ b/packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java
@@ -477,7 +477,7 @@
      *
      * <p>This method could be called frequently if there is a severe problem on the device.
      */
-    public void onPackageFailure(@NonNull List<VersionedPackage> packages,
+    public void notifyPackageFailure(@NonNull List<VersionedPackage> packages,
             @FailureReasons int failureReason) {
         if (packages == null) {
             Slog.w(TAG, "Could not resolve a list of failing packages");
@@ -488,7 +488,7 @@
             if (Flags.recoverabilityDetection()) {
                 if (now >= mLastMitigation
                         && (now - mLastMitigation) < getMitigationWindowMs()) {
-                    Slog.i(TAG, "Skipping onPackageFailure mitigation");
+                    Slog.i(TAG, "Skipping notifyPackageFailure mitigation");
                     return;
                 }
             }
@@ -515,7 +515,7 @@
                             ObserverInternal observer = mAllObservers.valueAt(oIndex);
                             PackageHealthObserver registeredObserver = observer.registeredObserver;
                             if (registeredObserver != null
-                                    && observer.onPackageFailureLocked(
+                                    && observer.notifyPackageFailureLocked(
                                     versionedPackage.getPackageName())) {
                                 MonitoredPackage p = observer.getMonitoredPackage(
                                         versionedPackage.getPackageName());
@@ -714,7 +714,7 @@
         // Check if native watchdog reported a crash
         if ("1".equals(SystemProperties.get("sys.init.updatable_crashing"))) {
             // We rollback all available low impact rollbacks when crash is unattributable
-            onPackageFailure(Collections.EMPTY_LIST, FAILURE_REASON_NATIVE_CRASH);
+            notifyPackageFailure(Collections.EMPTY_LIST, FAILURE_REASON_NATIVE_CRASH);
             // we stop polling after an attempt to execute rollback, regardless of whether the
             // attempt succeeds or not
         } else {
@@ -926,7 +926,7 @@
      * effectively behave as if the explicit health check hasn't passed for {@code packageName}.
      *
      * <p> {@code packageName} can still be considered failed if reported by
-     * {@link #onPackageFailureLocked} before the package expires.
+     * {@link #notifyPackageFailureLocked} before the package expires.
      *
      * <p> Triggered by components outside the system server when they are fully functional after an
      * update.
@@ -1253,7 +1253,7 @@
                         return;
                     }
                     final List<VersionedPackage> pkgList = Collections.singletonList(pkg);
-                    onPackageFailure(pkgList, FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
+                    notifyPackageFailure(pkgList, FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
                 });
     }
 
@@ -1467,7 +1467,7 @@
          * @hide
          */
         @GuardedBy("mLock")
-        public boolean onPackageFailureLocked(String packageName) {
+        public boolean notifyPackageFailureLocked(String packageName) {
             if (getMonitoredPackage(packageName) == null && registeredObserver.isPersistent()
                     && registeredObserver.mayObservePackage(packageName)) {
                 putMonitoredPackage(sPackageWatchdog.newMonitoredPackage(
diff --git a/packages/NeuralNetworks/OWNERS b/packages/NeuralNetworks/OWNERS
new file mode 100644
index 0000000..6b39150
--- /dev/null
+++ b/packages/NeuralNetworks/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 195575
+
+sandeepbandaru@google.com
+shivanker@google.com
+shiqing@google.com
\ No newline at end of file
diff --git a/packages/PackageInstaller/res/values-it/strings.xml b/packages/PackageInstaller/res/values-it/strings.xml
index 1561e79..ec6d3fc 100644
--- a/packages/PackageInstaller/res/values-it/strings.xml
+++ b/packages/PackageInstaller/res/values-it/strings.xml
@@ -43,7 +43,7 @@
     <string name="unknown_apps_admin_dlg_text" msgid="4456572224020176095">"L\'amministratore non consente l\'installazione di app ottenute da origini sconosciute"</string>
     <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Questo utente non può installare app sconosciute"</string>
     <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"L\'utente non dispone dell\'autorizzazione a installare app"</string>
-    <string name="ok" msgid="7871959885003339302">"OK"</string>
+    <string name="ok" msgid="7871959885003339302">"Ok"</string>
     <string name="archive" msgid="4447791830199354721">"Archivia"</string>
     <string name="update_anyway" msgid="8792432341346261969">"Aggiorna comunque"</string>
     <string name="manage_applications" msgid="5400164782453975580">"Gestisci app"</string>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-af/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-af/strings.xml
index 38cae30..7209cc2 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-af/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-af/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Kies \'n prent"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Neem \'n foto"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Kies ’n profielprent"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Verstekgebruikerikoon"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Klaar"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-am/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-am/strings.xml
index 917a2fd..713e0d95 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-am/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-am/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"ምስል ይምረጡ"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"ፎቶ ያንሱ"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"የመገለጫ ሥዕል ይምረጡ"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"ነባሪ የተጠቃሚ አዶ"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"ተከናውኗል"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ar/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ar/strings.xml
index 8e5231b..1b5dbc0 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-ar/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-ar/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"اختيار صورة"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"التقاط صورة"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"اختيار صورة للملف الشخصي"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"رمز المستخدم التلقائي"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"تم"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-as/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-as/strings.xml
index c77b573..6281328 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-as/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-as/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"এখন প্ৰতিচ্ছবি বাছনি কৰক"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"এখন ফট’ তোলক"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"এখন প্ৰ’ফাইল চিত্ৰ বাছনি কৰক"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"ডিফ’ল্ট ব্যৱহাৰকাৰীৰ চিহ্ন"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"কৰা হ’ল"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-az/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-az/strings.xml
index 6871473..d47ffce 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-az/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-az/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Şəkil seçin"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Foto çəkin"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Profil şəkli seçin"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Defolt istifadəçi ikonası"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Hazırdır"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-b+sr+Latn/strings.xml
index 42fb478..886bd5d 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-b+sr+Latn/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Odaberite sliku"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Slikajte"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Odaberite sliku profila"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Podrazumevana ikona korisnika"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Gotovo"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-be/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-be/strings.xml
index c2ef4db..38a1340 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-be/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-be/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Выбраць відарыс"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Зрабіць фота"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Выберыце відарыс профілю"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Стандартны карыстальніцкі значок"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Гатова"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-bg/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-bg/strings.xml
index eeca7d8..90e78b5 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-bg/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-bg/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Избиране на изображение"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Правене на снимка"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Изберете снимка на потребителския профил"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Икона за основния потребител"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Готово"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-bn/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-bn/strings.xml
index 6d4d29f..c56c9da 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-bn/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-bn/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"একটি ছবি বেছে নিন"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"ফটো তুলুন"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"কোনও একটি প্রোফাইল ছবি বেছে নিন"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"ডিফল্ট ব্যবহারকারীর আইকন"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"হয়ে গেছে"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-bs/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-bs/strings.xml
index def1b45..1dd707d 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-bs/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-bs/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Odaberite sliku"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Snimite fotografiju"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Odaberite sliku profila"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Zadana ikona korisnika"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Gotovo"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ca/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ca/strings.xml
index 1b613ca..d8d3171 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-ca/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-ca/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Tria una imatge"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Fes una foto"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Tria una foto de perfil"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Icona d\'usuari predeterminat"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Fet"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-cs/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-cs/strings.xml
index ffe2f47..6ee5b3e 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-cs/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-cs/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Zvolit obrázek"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Vyfotit"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Vyberte profilový obrázek"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Výchozí uživatelská ikona"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Hotovo"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-da/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-da/strings.xml
index ab01eef..0583399 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-da/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-da/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Vælg et billede"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Tag et billede"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Vælg et profilbillede"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Ikon for standardbruger"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Udfør"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-de/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-de/strings.xml
index 4d6c651a..345b4fa 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-de/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-de/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Bild auswählen"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Foto aufnehmen"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Profilbild auswählen"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Standardmäßiges Nutzersymbol"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Fertig"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-el/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-el/strings.xml
index 9e6813f..7cecd45 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-el/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-el/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Επιλέξτε μια εικόνα"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Λήψη φωτογραφίας"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Επιλογή φωτογραφ­ίας προφίλ"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Προεπιλεγμένο εικονίδιο χρήστη"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Τέλος"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-en-rAU/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-en-rAU/strings.xml
index d0aae79..f9905d0 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-en-rAU/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Choose an image"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Take a photo"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Choose a profile picture"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Default user icon"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Done"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-en-rGB/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-en-rGB/strings.xml
index d0aae79..f9905d0 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-en-rGB/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Choose an image"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Take a photo"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Choose a profile picture"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Default user icon"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Done"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-en-rIN/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-en-rIN/strings.xml
index d0aae79..f9905d0 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-en-rIN/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Choose an image"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Take a photo"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Choose a profile picture"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Default user icon"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Done"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-es-rUS/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-es-rUS/strings.xml
index 296dcc8..8e9d407 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-es-rUS/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Elegir una imagen"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Tomar una foto"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Elige una foto de perfil"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Ícono de usuario predeterminado"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Listo"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-es/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-es/strings.xml
index 5d4a8d2..a7da134 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-es/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-es/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Seleccionar una imagen"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Hacer una foto"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Elige una imagen de perfil"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Icono de usuario predeterminado"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Hecho"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-et/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-et/strings.xml
index ecd3a83..ecf140d 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-et/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-et/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Vali pilt"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Pildista"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Profiilipildi valimine"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Vaikekasutajaikoon"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Valmis"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-eu/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-eu/strings.xml
index e29bc11..c55d559 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-eu/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-eu/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Aukeratu irudi bat"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Atera argazki bat"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Aukeratu profileko argazki bat"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Erabiltzaile lehenetsiaren ikonoa"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Eginda"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-fa/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-fa/strings.xml
index 25efac4..7db55cf 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-fa/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-fa/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"انتخاب تصویر"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"عکس گرفتن"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"انتخاب عکس نمایه"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"نماد کاربر پیش‌فرض"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"تمام"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-fi/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-fi/strings.xml
index 4d805ed..7a0cca1 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-fi/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-fi/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Valitse kuva"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Ota kuva"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Valitse profiilikuva"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Oletuskäyttäjäkuvake"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Valmis"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-fr-rCA/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-fr-rCA/strings.xml
index fb32c5b..e439471 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-fr-rCA/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Sélectionner une image"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Prendre une photo"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Choisir une photo de profil"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Icône d\'utilisateur par défaut"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Terminé"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-fr/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-fr/strings.xml
index 79620e9..2ffeb43 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-fr/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-fr/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Choisir une image"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Prendre une photo"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Choisir une photo de profil"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Icône de l\'utilisateur par défaut"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"OK"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-gl/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-gl/strings.xml
index bbfa18b..5e46474 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-gl/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-gl/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Escoller unha imaxe"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Tirar unha foto"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Escoller unha imaxe do perfil"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Icona do usuario predeterminado"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Feito"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-gu/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-gu/strings.xml
index 247afe1..96e6753 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-gu/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-gu/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"છબી પસંદ કરો"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"ફોટો લો"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"પ્રોફાઇલ ફોટો પસંદ કરો"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"ડિફૉલ્ટ વપરાશકર્તાનું આઇકન"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"થઈ ગયું"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-hi/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-hi/strings.xml
index 3c51576..0878ff2 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-hi/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-hi/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"इमेज चुनें"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"फ़ोटो खींचें"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"प्रोफ़ाइल फ़ोटो चुनें"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"उपयोगकर्ता के लिए डिफ़ॉल्ट आइकॉन"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"हो गया"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-hr/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-hr/strings.xml
index e9a56bd..b599ddf 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-hr/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-hr/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Odaberite sliku"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Snimi fotografiju"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Odaberite profilnu sliku"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Ikona zadanog korisnika"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Gotovo"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-hu/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-hu/strings.xml
index f3d53cd..55f4a60 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-hu/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-hu/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Kép kiválasztása"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Fotó készítése"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Profilkép választása"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Alapértelmezett felhasználó ikonja"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Kész"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-in/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-in/strings.xml
index bfa0d93..9b5cbf3 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-in/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-in/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Pilih gambar"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Ambil foto"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Pilih foto profil"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Ikon pengguna default"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Selesai"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-is/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-is/strings.xml
index d496524..4007c38 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-is/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-is/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Velja mynd"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Taka mynd"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Veldu prófílmynd"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Tákn sjálfgefins notanda"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Lokið"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-it/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-it/strings.xml
index 3ba0a01..caeb93b 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-it/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-it/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Scegli un\'immagine"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Scatta una foto"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Scegli un\'immagine del profilo"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Icona dell\'utente predefinito"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Fine"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-iw/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-iw/strings.xml
index 903989d..03ca68e 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-iw/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-iw/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"לבחירת תמונה"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"צילום תמונה"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"בחירה של תמונת הפרופיל"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"סמל המשתמש שמוגדר כברירת מחדל"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"סיום"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ka/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ka/strings.xml
index 817180b..ae61afc 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-ka/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-ka/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"სურათის არჩევა"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"ფოტოს გადაღება"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"პროფილის სურათის არჩევა"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"მომხმარებლის ნაგულისხმევი ხატულა"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"მზადაა"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-kk/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-kk/strings.xml
index ec01801..f1e8950 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-kk/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-kk/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Кескін таңдау"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Суретке түсіру"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Профиль суретін таңдау"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Әдепкі пайдаланушы белгішесі"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Дайын"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-km/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-km/strings.xml
index 7a31122..a86491e 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-km/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-km/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"ជ្រើសរើស​រូបភាព"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"ថតរូប"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"ជ្រើសរើសរូបភាពកម្រងព័ត៌មាន"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"រូបអ្នកប្រើប្រាស់លំនាំដើម"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"រួចរាល់"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ko/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ko/strings.xml
index 45bfb53..682ebfd 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-ko/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-ko/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"이미지 선택"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"사진 찍기"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"프로필 사진 선택"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"기본 사용자 아이콘"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"완료"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ky/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ky/strings.xml
index b3d39de..3d8e7bf 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-ky/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-ky/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Сүрөт тандоо"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Сүрөткө тартуу"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Профилдин сүрөтүн тандоо"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Демейки колдонуучунун сүрөтчөсү"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Бүттү"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-lo/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-lo/strings.xml
index 3ba6709..64bd871 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-lo/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-lo/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"ເລືອກຮູບ"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"ຖ່າຍຮູບ"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"ເລືອກຮູບໂປຣໄຟລ໌"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"ໄອຄອນຜູ້ໃຊ້ເລີ່ມຕົ້ນ"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"ແລ້ວໆ"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-lt/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-lt/strings.xml
index b0c0c39..4bc183b 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-lt/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-lt/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Pasirinkti vaizdą"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Fotografuoti"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Profilio nuotraukos pasirinkimas"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Numatytojo naudotojo piktograma"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Atlikta"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-lv/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-lv/strings.xml
index e664c80..72e6ec4 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-lv/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-lv/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Izvēlēties attēlu"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Uzņemt fotoattēlu"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Profila attēla izvēle"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Noklusējuma lietotāja ikona"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Gatavs"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-mk/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-mk/strings.xml
index bb0e247..4b6939e 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-mk/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-mk/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Изберете слика"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Фотографирај"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Изберете профилна слика"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Икона за стандарден корисник"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Готово"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ml/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ml/strings.xml
index 674b4f5..aec39b1 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-ml/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-ml/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"ഒരു ചിത്രം തിരഞ്ഞെടുക്കുക"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"ഒരു ഫോട്ടോ എടുക്കുക"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"പ്രൊഫൈൽ ചിത്രം തിരഞ്ഞെടുക്കുക"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"ഡിഫോൾട്ട് ഉപയോക്തൃ ഐക്കൺ"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"പൂർത്തിയായി"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-mn/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-mn/strings.xml
index 61553b5..4d13e87 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-mn/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-mn/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Зураг сонгох"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Зураг авах"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Профайл зураг сонгох"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Өгөгдмөл хэрэглэгчийн дүрс тэмдэг"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Болсон"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ms/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ms/strings.xml
index 2599696..45f1b36 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-ms/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-ms/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Pilih imej"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Ambil foto"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Pilih gambar profil"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Ikon pengguna lalai"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Selesai"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-my/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-my/strings.xml
index f9f697b..6973084 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-my/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-my/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"ပုံရွေးရန်"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"ဓာတ်ပုံရိုက်ရန်"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"ပရိုဖိုင်ပုံ ရွေးပါ"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"မူရင်းအသုံးပြုသူ သင်္ကေတ"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"ပြီးပြီ"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-nb/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-nb/strings.xml
index c1b7631..8a55006 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-nb/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-nb/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Velg et bilde"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Ta et bilde"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Velg et profilbilde"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Standard brukerikon"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Ferdig"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ne/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ne/strings.xml
index a8c02b9..8373058 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-ne/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-ne/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"कुनै फोटो छनौट गर्नुहोस्"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"फोटो खिच्नुहोस्"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"प्रोफाइल फोटो छान्नुहोस्"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"प्रयोगकर्ताको डिफल्ट आइकन"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"सम्पन्न भयो"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-nl/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-nl/strings.xml
index 47352bc..cb3bd51 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-nl/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-nl/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Een afbeelding kiezen"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Een foto maken"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Kies een profielfoto"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Standaard gebruikersicoon"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Klaar"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-or/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-or/strings.xml
index 132b97a..dd54ac3 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-or/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-or/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"ଗୋଟିଏ ଛବି ବାଛନ୍ତୁ"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"ଗୋଟିଏ ଫଟୋ ଉଠାନ୍ତୁ"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"ଏକ ପ୍ରୋଫାଇଲ ଛବି ବାଛନ୍ତୁ"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"ଡିଫଲ୍ଟ ୟୁଜର ଆଇକନ"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"ହୋଇଗଲା"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-pl/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-pl/strings.xml
index 7db7904..35787c9 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-pl/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-pl/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Wybierz obraz"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Zrób zdjęcie"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Wybierz zdjęcie profilowe"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Ikona domyślnego użytkownika"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Gotowe"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-pt-rBR/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-pt-rBR/strings.xml
index ae3e6e5..ba1ce2a 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-pt-rBR/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Escolher uma imagem"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Tirar uma foto"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Escolha uma foto de perfil"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Ícone de usuário padrão"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Concluir"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-pt/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-pt/strings.xml
index ae3e6e5..ba1ce2a 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-pt/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-pt/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Escolher uma imagem"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Tirar uma foto"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Escolha uma foto de perfil"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Ícone de usuário padrão"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Concluir"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ro/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ro/strings.xml
index ce662d4..51bcd57 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-ro/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-ro/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Alege o imagine"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Fă o fotografie"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Alege o fotografie de profil"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Pictograma prestabilită a utilizatorului"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Gata"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-ru/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-ru/strings.xml
index 47f8a83..59fb913 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-ru/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-ru/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Выбрать фото"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Сделать снимок"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Выберите фото профиля"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Значок пользователя по умолчанию"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Готово"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-si/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-si/strings.xml
index aaba442..db7e0b8 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-si/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-si/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"රූපයක් තෝරන්න"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"ඡායාරූපයක් ගන්න"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"පැතිකඩ පින්තූරයක් තේරීම"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"පෙරනිමි පරිශීලක නිරූපකය"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"නිමයි"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-sk/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-sk/strings.xml
index 3f801a3..36e94f3 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-sk/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-sk/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Vybrať obrázok"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Odfotiť"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Vyberte profilovú fotku"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Predvolená ikona používateľa"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Hotovo"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-sq/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-sq/strings.xml
index 0b8a58d..0093380 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-sq/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-sq/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Zgjidh një imazh"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Bëj një fotografi"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Zgjidh një fotografi profili"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Ikona e parazgjedhur e përdoruesit"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"U krye"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-sr/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-sr/strings.xml
index 1014df4..971d8c5 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-sr/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-sr/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Одаберите слику"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Сликајте"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Одаберите слику профила"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Подразумевана икона корисника"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Готово"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-sv/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-sv/strings.xml
index 8203409..9196e2a 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-sv/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-sv/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Välj en bild"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Ta ett foto"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Välj en profilbild"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Ikon för standardanvändare"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Klar"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-sw/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-sw/strings.xml
index b0e8c44..a0bc554 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-sw/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-sw/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Chagua picha"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Piga picha"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Chagua picha ya wasifu"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Aikoni chaguomsingi ya mtumiaji"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Nimemaliza"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-th/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-th/strings.xml
index 31e753e..b8b4324 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-th/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-th/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"เลือกรูปภาพ"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"ถ่ายรูป"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"เลือกรูปโปรไฟล์"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"ไอคอนผู้ใช้เริ่มต้น"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"เสร็จสิ้น"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-tr/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-tr/strings.xml
index 26d96c2..3e10257 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-tr/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-tr/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Resim seç"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Fotoğraf çek"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Profil fotoğrafı seçin"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Varsayılan kullanıcı simgesi"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Bitti"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-uk/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-uk/strings.xml
index 1fbe5fb..ee4a2fc 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-uk/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-uk/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Вибрати зображення"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Зробити фото"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Виберіть зображення профілю"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Значок користувача за умовчанням"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Готово"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-vi/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-vi/strings.xml
index 036c006..c6b4ef5 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-vi/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-vi/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Chọn hình ảnh"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Chụp ảnh"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Chọn một ảnh hồ sơ"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Biểu tượng người dùng mặc định"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Xong"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-zh-rCN/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-zh-rCN/strings.xml
index 58488b3..684449f 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-zh-rCN/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"选择图片"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"拍照"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"选择个人资料照片"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"默认用户图标"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"完成"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-zh-rHK/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-zh-rHK/strings.xml
index e5f3752..e0d4052 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-zh-rHK/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"選擇圖片"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"拍攝相片"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"選擇個人檔案相片"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"預設使用者圖示"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"完成"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-zh-rTW/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-zh-rTW/strings.xml
index 4a58180b..d82ad7e 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-zh-rTW/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"選擇圖片"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"拍照"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"選擇個人資料相片"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"預設使用者圖示"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"完成"</string>
 </resources>
diff --git a/packages/SettingsLib/AvatarPicker/res/values-zu/strings.xml b/packages/SettingsLib/AvatarPicker/res/values-zu/strings.xml
index ad15f89..8678332 100644
--- a/packages/SettingsLib/AvatarPicker/res/values-zu/strings.xml
+++ b/packages/SettingsLib/AvatarPicker/res/values-zu/strings.xml
@@ -19,9 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="user_image_choose_photo" msgid="5630717762469961028">"Khetha isithombe"</string>
     <string name="user_image_take_photo" msgid="3147097821937166738">"Thatha isithombe"</string>
-    <!-- no translation found for avatar_picker_title (7478146965334560463) -->
-    <skip />
+    <string name="avatar_picker_title" msgid="7478146965334560463">"Khetha isithombe sephrofayela"</string>
     <string name="default_user_icon_description" msgid="6018582161341388812">"Isithonjana somsebenzisi sokuzenzakalelayo"</string>
-    <!-- no translation found for done (3587741621903511576) -->
-    <skip />
+    <string name="done" msgid="3587741621903511576">"Kwenziwe"</string>
 </resources>
diff --git a/packages/SettingsLib/IntroPreference/src/com/android/settingslib/widget/IntroPreference.kt b/packages/SettingsLib/IntroPreference/src/com/android/settingslib/widget/IntroPreference.kt
index 0cdfc66..f9931cf 100644
--- a/packages/SettingsLib/IntroPreference/src/com/android/settingslib/widget/IntroPreference.kt
+++ b/packages/SettingsLib/IntroPreference/src/com/android/settingslib/widget/IntroPreference.kt
@@ -31,7 +31,7 @@
     attrs: AttributeSet? = null,
     defStyleAttr: Int = 0,
     defStyleRes: Int = 0
-) : Preference(context, attrs, defStyleAttr, defStyleRes) {
+) : Preference(context, attrs, defStyleAttr, defStyleRes), GroupSectionDividerMixin {
 
     private var isCollapsable: Boolean = false
     private var minLines: Int = 2
@@ -68,6 +68,7 @@
         (holder.findViewById(R.id.collapsable_summary) as? CollapsableTextView)?.apply {
             setCollapsable(isCollapsable)
             setMinLines(minLines)
+            visibility = if (summary.isNullOrEmpty()) View.GONE else View.VISIBLE
             setText(summary.toString())
             if (hyperlinkListener != null) {
                 setHyperlinkListener(hyperlinkListener)
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceDataStoreAdapter.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceDataStoreAdapter.kt
index c2728b4..7601b9a 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceDataStoreAdapter.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceDataStoreAdapter.kt
@@ -20,7 +20,7 @@
 import com.android.settingslib.datastore.KeyValueStore
 
 /** Adapter to translate [KeyValueStore] into [PreferenceDataStore]. */
-class PreferenceDataStoreAdapter(private val keyValueStore: KeyValueStore) : PreferenceDataStore() {
+class PreferenceDataStoreAdapter(val keyValueStore: KeyValueStore) : PreferenceDataStore() {
 
     override fun getBoolean(key: String, defValue: Boolean): Boolean =
         keyValueStore.getValue(key, Boolean::class.javaObjectType) ?: defValue
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt
index 62ac3ad..7cec59c 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt
@@ -74,16 +74,12 @@
     private val preferences: ImmutableMap<String, PreferenceHierarchyNode>
     private val dependencies: ImmutableMultimap<String, String>
     private val lifecycleAwarePreferences: Array<PreferenceLifecycleProvider>
-    private val storages = mutableSetOf<KeyedObservable<String>>()
+    private val storages = mutableMapOf<String, KeyedObservable<String>>()
 
     private val preferenceObserver: KeyedObserver<String?>
 
     private val storageObserver =
-        KeyedObserver<String?> { key, _ ->
-            if (key != null) {
-                notifyChange(key, CHANGE_REASON_VALUE)
-            }
-        }
+        KeyedObserver<String> { key, _ -> notifyChange(key, CHANGE_REASON_VALUE) }
 
     init {
         val preferencesBuilder = ImmutableMap.builder<String, PreferenceHierarchyNode>()
@@ -98,7 +94,6 @@
                 preferencesBuilder.put(it.key, this)
                 it.dependencyOfEnabledState(context)?.addDependency(it)
                 if (it is PreferenceLifecycleProvider) lifecycleAwarePreferences.add(it)
-                if (it is PersistentPreference<*>) storages.add(it.storage(context))
             }
         }
 
@@ -120,7 +115,16 @@
 
         preferenceObserver = KeyedObserver { key, reason -> onPreferenceChange(key, reason) }
         addObserver(preferenceObserver, mainExecutor)
-        for (storage in storages) storage.addObserver(storageObserver, mainExecutor)
+
+        preferenceScreen.forEachRecursively {
+            val preferenceDataStore = it.preferenceDataStore
+            if (preferenceDataStore is PreferenceDataStoreAdapter) {
+                val key = it.key
+                val keyValueStore = preferenceDataStore.keyValueStore
+                storages[key] = keyValueStore
+                keyValueStore.addObserver(key, storageObserver, mainExecutor)
+            }
+        }
     }
 
     private fun onPreferenceChange(key: String?, reason: Int) {
@@ -181,7 +185,7 @@
 
     fun onDestroy() {
         removeObserver(preferenceObserver)
-        for (storage in storages) storage.removeObserver(storageObserver)
+        for ((key, storage) in storages) storage.removeObserver(key, storageObserver)
         for (preference in lifecycleAwarePreferences) {
             preference.onDestroy(preferenceLifecycleContext)
         }
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/Utils.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/Utils.kt
new file mode 100644
index 0000000..2e7221b
--- /dev/null
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/Utils.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.settingslib.preference
+
+import androidx.preference.Preference
+import androidx.preference.PreferenceGroup
+
+/** Traversals preference hierarchy recursively and applies an action. */
+fun PreferenceGroup.forEachRecursively(action: (Preference) -> Unit) {
+    action.invoke(this)
+    for (index in 0 until preferenceCount) {
+        val preference = getPreference(index)
+        if (preference is PreferenceGroup) {
+            preference.forEachRecursively(action)
+        } else {
+            action.invoke(preference)
+        }
+    }
+}
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-hi/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-hi/strings.xml
index b5534b9..6de8438 100644
--- a/packages/SettingsLib/RestrictedLockUtils/res/values-hi/strings.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-hi/strings.xml
@@ -18,5 +18,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="enabled_by_admin" msgid="6630472777476410137">"एडमिन की ओर से चालू किया गया"</string>
-    <string name="disabled_by_admin" msgid="4023569940620832713">"एडमिन ने यह सुविधा बंद की है"</string>
+    <string name="disabled_by_admin" msgid="4023569940620832713">"एडमिन ने यह सुविधा बंद की हुई है"</string>
 </resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-hu/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-hu/strings.xml
index 2ab8142..ecfa2c7 100644
--- a/packages/SettingsLib/RestrictedLockUtils/res/values-hu/strings.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-hu/strings.xml
@@ -18,5 +18,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="enabled_by_admin" msgid="6630472777476410137">"A rendszergazda bekapcsolta"</string>
-    <string name="disabled_by_admin" msgid="4023569940620832713">"A rendszergazda kikapcsolta"</string>
+    <string name="disabled_by_admin" msgid="4023569940620832713">"A rendszergazda letiltotta"</string>
 </resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-af/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-af/strings.xml
new file mode 100644
index 0000000..eb48b4e
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-af/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Vou uit"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Vou in"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-am/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-am/strings.xml
new file mode 100644
index 0000000..4428192
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-am/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"ዘርጋ"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"ሰብስብ"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-ar/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ar/strings.xml
new file mode 100644
index 0000000..e6d4c7b
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-ar/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"توسيع"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"تصغير"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-as/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-as/strings.xml
new file mode 100644
index 0000000..2b5a5c9
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-as/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"বিস্তাৰ কৰক"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"সংকোচন কৰক"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-az/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-az/strings.xml
new file mode 100644
index 0000000..c7adee3
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-az/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Genişləndirin"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Yığcamlaşdırın"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..8b245a6
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Proširi"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Skupi"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-be/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-be/strings.xml
new file mode 100644
index 0000000..b468f81
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-be/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Разгарнуць"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Згарнуць"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-bg/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-bg/strings.xml
new file mode 100644
index 0000000..b177fa7
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-bg/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Разгъване"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Свиване"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-bn/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-bn/strings.xml
new file mode 100644
index 0000000..67bb59f
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-bn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"বড় করুন"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"আড়াল করুন"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-bs/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-bs/strings.xml
new file mode 100644
index 0000000..31afc8b
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-bs/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Proširi"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Suzi"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-ca/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ca/strings.xml
new file mode 100644
index 0000000..0f999c9
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-ca/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Desplega"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Replega"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-cs/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-cs/strings.xml
new file mode 100644
index 0000000..144dba8
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-cs/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Rozbalit"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Sbalit"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-da/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-da/strings.xml
new file mode 100644
index 0000000..85497f1
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-da/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Udvid"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Skjul"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-de/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-de/strings.xml
new file mode 100644
index 0000000..9e47741
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-de/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Maximieren"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Minimieren"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-el/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-el/strings.xml
new file mode 100644
index 0000000..0b325b5
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-el/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Ανάπτυξη"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Σύμπτυξη"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-en-rAU/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..2539aa0
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-en-rAU/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Expand"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Collapse"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-en-rGB/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..2539aa0
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-en-rGB/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Expand"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Collapse"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-en-rIN/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..2539aa0
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-en-rIN/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Expand"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Collapse"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-es-rUS/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..c976a2e
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-es-rUS/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Expandir"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Contraer"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-es/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-es/strings.xml
new file mode 100644
index 0000000..72ba9d1
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-es/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Mostrar"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Ocultar"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-et/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-et/strings.xml
new file mode 100644
index 0000000..8563606
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-et/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Laienda"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Ahenda"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-eu/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-eu/strings.xml
new file mode 100644
index 0000000..d8c2c35
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-eu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Zabaldu"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Tolestu"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-fa/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-fa/strings.xml
new file mode 100644
index 0000000..2408741
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-fa/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"ازهم بازکردن"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"جمع کردن"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-fi/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-fi/strings.xml
new file mode 100644
index 0000000..0d226bf
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-fi/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Laajenna"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Tiivistä"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-fr-rCA/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..fecfaa2
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-fr-rCA/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Développer"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Réduire"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-fr/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-fr/strings.xml
new file mode 100644
index 0000000..fecfaa2
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-fr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Développer"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Réduire"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-gl/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-gl/strings.xml
new file mode 100644
index 0000000..7999aa1
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-gl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Despregar"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Contraer"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-gu/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-gu/strings.xml
new file mode 100644
index 0000000..1457d34
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-gu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"મોટું કરો"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"નાનું કરો"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-hi/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-hi/strings.xml
new file mode 100644
index 0000000..856379a
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-hi/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"बड़ा करें"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"छोटा करें"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-hr/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-hr/strings.xml
new file mode 100644
index 0000000..2d637f4
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-hr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Proširi"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Sažmi"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-hu/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-hu/strings.xml
new file mode 100644
index 0000000..4273163
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-hu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Kibontás"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Összecsukás"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-in/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-in/strings.xml
new file mode 100644
index 0000000..97c1d602
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-in/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Luaskan"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Ciutkan"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-is/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-is/strings.xml
new file mode 100644
index 0000000..cc4d05b
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-is/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Stækka"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Minnka"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-it/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-it/strings.xml
new file mode 100644
index 0000000..8edcf24
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-it/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Espandi"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Comprimi"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-iw/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-iw/strings.xml
new file mode 100644
index 0000000..784bd8e
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-iw/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"הרחבה"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"כיווץ"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-ka/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ka/strings.xml
new file mode 100644
index 0000000..ec8f1dd
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-ka/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"გაფართოება"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"ჩაკეცვა"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-kk/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-kk/strings.xml
new file mode 100644
index 0000000..329ccbb
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-kk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Жаю"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Жию"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-km/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-km/strings.xml
new file mode 100644
index 0000000..5ca0269
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-km/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"ពង្រីក"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"បង្រួម"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-ko/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ko/strings.xml
new file mode 100644
index 0000000..05d4921
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-ko/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"펼치기"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"접기"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-ky/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ky/strings.xml
new file mode 100644
index 0000000..4f5b8dc
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-ky/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Жайып көрсөтүү"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Жыйыштыруу"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-lo/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-lo/strings.xml
new file mode 100644
index 0000000..d6ec479
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-lo/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"ຂະຫຍາຍ"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"ຫຍໍ້ລົງ"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-lt/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-lt/strings.xml
new file mode 100644
index 0000000..54076c4
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-lt/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Išskleisti"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Sutraukti"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-lv/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-lv/strings.xml
new file mode 100644
index 0000000..2f87b0e
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-lv/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Izvērst"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Sakļaut"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-mk/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-mk/strings.xml
new file mode 100644
index 0000000..b4f8fb9
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-mk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Прошири"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Собери"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-ml/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ml/strings.xml
new file mode 100644
index 0000000..c68141e
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-ml/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"വികസിപ്പിക്കുക"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"ചുരുക്കുക"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-mn/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-mn/strings.xml
new file mode 100644
index 0000000..86b333d
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-mn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Дэлгэх"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Хураах"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-ms/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ms/strings.xml
new file mode 100644
index 0000000..1ffa5a0
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-ms/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Kembangkan"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Kuncupkan"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-my/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-my/strings.xml
new file mode 100644
index 0000000..6f79acc
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-my/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"ပိုပြပါ"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"လျှော့ပြပါ"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-nb/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-nb/strings.xml
new file mode 100644
index 0000000..359c9ab
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-nb/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Vis"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Skjul"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-ne/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ne/strings.xml
new file mode 100644
index 0000000..374fd31
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-ne/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"एक्स्पान्ड गर्नुहोस्"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"कोल्याप्स गर्नुहोस्"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-nl/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-nl/strings.xml
new file mode 100644
index 0000000..76a4f99
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-nl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Uitvouwen"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Samenvouwen"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-or/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-or/strings.xml
new file mode 100644
index 0000000..1e1e870
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-or/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"ବିସ୍ତାର କରନ୍ତୁ"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-pl/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-pl/strings.xml
new file mode 100644
index 0000000..da273b3
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-pl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Rozwiń"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Zwiń"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-pt-rBR/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..4e3d0e6
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-pt-rBR/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Abrir"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Fechar"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-pt/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-pt/strings.xml
new file mode 100644
index 0000000..4e3d0e6
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-pt/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Abrir"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Fechar"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-ro/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ro/strings.xml
new file mode 100644
index 0000000..ec20884
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-ro/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Extinde"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Restrânge"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-ru/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ru/strings.xml
new file mode 100644
index 0000000..ba6ab96
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-ru/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Развернуть"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Свернуть"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-si/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-si/strings.xml
new file mode 100644
index 0000000..9adb646
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-si/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"දිග හරින්න"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"හකුළන්න"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-sk/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-sk/strings.xml
new file mode 100644
index 0000000..574ee83
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-sk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Rozbaliť"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Zbaliť"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-sq/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-sq/strings.xml
new file mode 100644
index 0000000..e02ecbf
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-sq/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Zgjero"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Palos"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-sr/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-sr/strings.xml
new file mode 100644
index 0000000..35f6aa3
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-sr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Прошири"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Скупи"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-sv/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-sv/strings.xml
new file mode 100644
index 0000000..2416839
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-sv/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Utöka"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Komprimera"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-sw/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-sw/strings.xml
new file mode 100644
index 0000000..9a60758
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-sw/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Panua"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Kunja"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-th/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-th/strings.xml
new file mode 100644
index 0000000..d6dce9c
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-th/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"ขยาย"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"ยุบ"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-tr/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-tr/strings.xml
new file mode 100644
index 0000000..8c7dbcf
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-tr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Genişlet"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Daralt"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-uk/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-uk/strings.xml
new file mode 100644
index 0000000..6da0ca8
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-uk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Розгорнути"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Згорнути"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-vi/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-vi/strings.xml
new file mode 100644
index 0000000..46f3351
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-vi/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Mở rộng"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Thu gọn"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-zh-rCN/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..ea5f29b
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-zh-rCN/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"展开"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"收起"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-zh-rHK/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..3620313
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-zh-rHK/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"展開"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"收合"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-zh-rTW/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..3620313
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-zh-rTW/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"展開"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"收合"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-zu/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-zu/strings.xml
new file mode 100644
index 0000000..725d8bc
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-zu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Nweba"</string>
+    <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Goqa"</string>
+</resources>
diff --git a/packages/SettingsLib/Spa/build.gradle.kts b/packages/SettingsLib/Spa/build.gradle.kts
index 73d0bec..02e1904 100644
--- a/packages/SettingsLib/Spa/build.gradle.kts
+++ b/packages/SettingsLib/Spa/build.gradle.kts
@@ -29,7 +29,7 @@
 
 allprojects {
     extra["androidTop"] = androidTop
-    extra["jetpackComposeVersion"] = "1.7.3"
+    extra["jetpackComposeVersion"] = "1.8.0-alpha06"
 }
 
 subprojects {
diff --git a/packages/SettingsLib/Spa/gradle/libs.versions.toml b/packages/SettingsLib/Spa/gradle/libs.versions.toml
index 272dc2d..74811d3 100644
--- a/packages/SettingsLib/Spa/gradle/libs.versions.toml
+++ b/packages/SettingsLib/Spa/gradle/libs.versions.toml
@@ -15,7 +15,7 @@
 #
 
 [versions]
-agp = "8.6.1"
+agp = "8.7.2"
 compose-compiler = "1.5.11"
 dexmaker-mockito = "2.28.3"
 jvm = "17"
diff --git a/packages/SettingsLib/Spa/gradle/wrapper/gradle-8.10.2-bin.zip b/packages/SettingsLib/Spa/gradle/wrapper/gradle-8.10.2-bin.zip
deleted file mode 100644
index 45f0424..0000000
--- a/packages/SettingsLib/Spa/gradle/wrapper/gradle-8.10.2-bin.zip
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/Spa/gradle/wrapper/gradle-8.11.1-bin.zip b/packages/SettingsLib/Spa/gradle/wrapper/gradle-8.11.1-bin.zip
new file mode 100644
index 0000000..f8c4ecb
--- /dev/null
+++ b/packages/SettingsLib/Spa/gradle/wrapper/gradle-8.11.1-bin.zip
Binary files differ
diff --git a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties
index 1c25e974..ca510eb 100644
--- a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties
+++ b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties
@@ -16,6 +16,6 @@
 
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=gradle-8.10.2-bin.zip
+distributionUrl=gradle-8.11.1-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/packages/SettingsLib/Spa/spa/build.gradle.kts b/packages/SettingsLib/Spa/spa/build.gradle.kts
index 914f06c..1f32ad6 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle.kts
+++ b/packages/SettingsLib/Spa/spa/build.gradle.kts
@@ -54,14 +54,14 @@
 dependencies {
     api(project(":SettingsLibColor"))
     api("androidx.appcompat:appcompat:1.7.0")
-    api("androidx.compose.material3:material3:1.4.0-alpha01")
-    api("androidx.compose.material:material-icons-extended:$jetpackComposeVersion")
+    api("androidx.compose.material3:material3:1.4.0-alpha04")
+    api("androidx.compose.material:material-icons-extended")
     api("androidx.compose.runtime:runtime-livedata:$jetpackComposeVersion")
     api("androidx.compose.ui:ui-tooling-preview:$jetpackComposeVersion")
     api("androidx.graphics:graphics-shapes-android:1.0.1")
     api("androidx.lifecycle:lifecycle-livedata-ktx")
     api("androidx.lifecycle:lifecycle-runtime-compose")
-    api("androidx.navigation:navigation-compose:2.8.1")
+    api("androidx.navigation:navigation-compose:2.9.0-alpha03")
     api("com.github.PhilJay:MPAndroidChart:v3.1.0-alpha")
     api("com.google.android.material:material:1.12.0")
     debugApi("androidx.compose.ui:ui-tooling:$jetpackComposeVersion")
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt
index ea6a272..7466f95 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt
@@ -41,8 +41,6 @@
 import com.android.settingslib.spaprivileged.model.app.IPackageManagers
 import com.android.settingslib.spaprivileged.model.app.PackageManagers
 import com.android.settingslib.spaprivileged.model.app.toRoute
-import com.android.settingslib.spaprivileged.model.enterprise.EnhancedConfirmation
-import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
 import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderFactory
 import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderImpl
 import com.android.settingslib.spaprivileged.template.preference.RestrictedSwitchPreference
@@ -155,12 +153,12 @@
             override val changeable = { isChangeable }
             override val onCheckedChange: (Boolean) -> Unit = { setAllowed(record, it) }
         }
-        val restrictions = Restrictions(userId = userId,
-            keys = switchRestrictionKeys,
-            enhancedConfirmation = enhancedConfirmationKey?.let { EnhancedConfirmation(
-                key = it,
-                packageName = packageName) })
-        RestrictedSwitchPreference(switchModel, restrictions, restrictionsProviderFactory)
+        RestrictedSwitchPreference(
+            model = switchModel,
+            restrictions = getRestrictions(userId, packageName),
+            ifBlockedByAdminOverrideCheckedValueTo = switchifBlockedByAdminOverrideCheckedValueTo,
+            restrictionsProviderFactory = restrictionsProviderFactory,
+        )
         InfoPageAdditionalContent(record, isAllowed)
     }
 }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt
index 627b248..d2867af1 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt
@@ -26,6 +26,8 @@
 import com.android.settingslib.spa.framework.compose.rememberContext
 import com.android.settingslib.spa.framework.util.asyncMapItem
 import com.android.settingslib.spaprivileged.model.app.AppRecord
+import com.android.settingslib.spaprivileged.model.enterprise.EnhancedConfirmation
+import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
 import kotlinx.coroutines.flow.Flow
 
 /**
@@ -38,6 +40,16 @@
     val switchRestrictionKeys: List<String>
         get() = emptyList()
 
+    /**
+     * If this is not null, and on a switch UI restricted by admin, the switch's checked status will
+     * be overridden.
+     *
+     * And if there is an admin summary, such as "Enabled by admin" or "Disabled by admin", will
+     * also be overridden.
+     */
+    val switchifBlockedByAdminOverrideCheckedValueTo: Boolean?
+        get() = null
+
     val enhancedConfirmationKey: String?
         get() = null
 
@@ -101,6 +113,16 @@
     record: T,
 ): Boolean = !record.isSystemOrRootUid() && isChangeable(record)
 
+fun <T : AppRecord> TogglePermissionAppListModel<T>.getRestrictions(
+    userId: Int,
+    packageName: String,
+) =
+    Restrictions(
+        userId = userId,
+        keys = switchRestrictionKeys,
+        enhancedConfirmation =
+            enhancedConfirmationKey?.let { key -> EnhancedConfirmation(key, packageName) },
+    )
 
 interface TogglePermissionAppListProvider {
     val permissionType: String
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt
index 57102ba..ec44d2a 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt
@@ -42,8 +42,6 @@
 import com.android.settingslib.spaprivileged.model.app.AppListModel
 import com.android.settingslib.spaprivileged.model.app.AppRecord
 import com.android.settingslib.spaprivileged.model.app.userId
-import com.android.settingslib.spaprivileged.model.enterprise.EnhancedConfirmation
-import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
 import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderFactory
 import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderImpl
 import com.android.settingslib.spaprivileged.model.enterprise.rememberRestrictedMode
@@ -151,23 +149,19 @@
 
     @Composable
     fun getSummary(record: T): () -> String {
-        val restrictions = remember(record.app.userId, record.app.packageName) {
-            Restrictions(
+        val restrictions =
+            listModel.getRestrictions(
                 userId = record.app.userId,
-                keys = listModel.switchRestrictionKeys,
-                enhancedConfirmation = listModel.enhancedConfirmationKey?.let {
-                    EnhancedConfirmation(
-                        key = it,
-                        packageName = record.app.packageName)
-                })
-        }
+                packageName = record.app.packageName,
+            )
         val restrictedMode by restrictionsProviderFactory.rememberRestrictedMode(restrictions)
         val allowed = listModel.isAllowed(record)
         return RestrictedSwitchPreferenceModel.getSummary(
             context = context,
-            restrictedModeSupplier = { restrictedMode },
             summaryIfNoRestricted = { getSummaryIfNoRestricted(allowed()) },
-            checked = allowed,
+            checkedIfNoRestricted = allowed,
+            checkedIfBlockedByAdmin = listModel.switchifBlockedByAdminOverrideCheckedValueTo,
+            restrictedModeSupplier = { restrictedMode },
         )
     }
 
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt
index cd72025..5fec110 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt
@@ -25,12 +25,25 @@
 import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderImpl
 import com.android.settingslib.spaprivileged.template.preference.RestrictedSwitchPreferenceModel.Companion.RestrictedSwitchWrapper
 
+/**
+ * @param ifBlockedByAdminOverrideCheckedValueTo if this is not null and there is an admin
+ *   restriction, the switch's checked status will be overridden.
+ *
+ *   And if there is an admin summary, such as "Enabled by admin" or "Disabled by admin", will also
+ *   be overridden.
+ */
 @Composable
 fun RestrictedSwitchPreference(
     model: SwitchPreferenceModel,
     restrictions: Restrictions,
+    ifBlockedByAdminOverrideCheckedValueTo: Boolean? = null,
 ) {
-    RestrictedSwitchPreference(model, restrictions, ::RestrictionsProviderImpl)
+    RestrictedSwitchPreference(
+        model = model,
+        restrictions = restrictions,
+        ifBlockedByAdminOverrideCheckedValueTo = ifBlockedByAdminOverrideCheckedValueTo,
+        restrictionsProviderFactory = ::RestrictionsProviderImpl,
+    )
 }
 
 @VisibleForTesting
@@ -38,13 +51,18 @@
 internal fun RestrictedSwitchPreference(
     model: SwitchPreferenceModel,
     restrictions: Restrictions,
+    ifBlockedByAdminOverrideCheckedValueTo: Boolean? = null,
     restrictionsProviderFactory: RestrictionsProviderFactory,
 ) {
     if (restrictions.isEmpty()) {
         SwitchPreference(model)
         return
     }
-    restrictionsProviderFactory.RestrictedSwitchWrapper(model, restrictions) {
+    restrictionsProviderFactory.RestrictedSwitchWrapper(
+        model = model,
+        restrictions = restrictions,
+        ifBlockedByAdminOverrideCheckedValueTo = ifBlockedByAdminOverrideCheckedValueTo,
+    ) {
         SwitchPreference(it)
     }
 }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceModel.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceModel.kt
index fb23637..0bb92ce 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceModel.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceModel.kt
@@ -42,26 +42,29 @@
     context: Context,
     model: SwitchPreferenceModel,
     private val restrictedMode: RestrictedMode?,
+    private val ifBlockedByAdminOverrideCheckedValueTo: Boolean?,
 ) : SwitchPreferenceModel {
     override val title = model.title
 
-    override val summary = getSummary(
-        context = context,
-        restrictedModeSupplier = { restrictedMode },
-        summaryIfNoRestricted = model.summary,
-        checked = model.checked,
-    )
+    override val checked =
+        when (restrictedMode) {
+            null -> ({ null })
+            is NoRestricted -> model.checked
+            is BaseUserRestricted -> ({ false })
+            is BlockedByAdmin -> ({ ifBlockedByAdminOverrideCheckedValueTo ?: model.checked() })
+            is BlockedByEcm -> model.checked
+        }
+
+    override val summary =
+        getSummary(
+            context = context,
+            restrictedModeSupplier = { restrictedMode },
+            summaryIfNoRestricted = model.summary,
+            checkedIfNoRestricted = checked,
+        )
 
     override val icon = model.icon
 
-    override val checked = when (restrictedMode) {
-        null -> ({ null })
-        is NoRestricted -> model.checked
-        is BaseUserRestricted -> ({ false })
-        is BlockedByAdmin -> model.checked
-        is BlockedByEcm -> model.checked
-    }
-
     override val changeable = restrictedMode.restrictEnabled(model.changeable)
 
     override val onCheckedChange = restrictedMode.restrictOnClick(model.onCheckedChange)
@@ -112,12 +115,20 @@
         fun RestrictedSwitchWrapper(
             model: SwitchPreferenceModel,
             restrictedMode: RestrictedMode?,
+            ifBlockedByAdminOverrideCheckedValueTo: Boolean? = null,
             content: @Composable (SwitchPreferenceModel) -> Unit,
         ) {
             val context = LocalContext.current
-            val restrictedSwitchPreferenceModel = remember(restrictedMode, model) {
-                RestrictedSwitchPreferenceModel(context, model, restrictedMode)
-            }
+            val restrictedSwitchPreferenceModel =
+                remember(restrictedMode, model) {
+                    RestrictedSwitchPreferenceModel(
+                        context = context,
+                        model = model,
+                        restrictedMode = restrictedMode,
+                        ifBlockedByAdminOverrideCheckedValueTo =
+                            ifBlockedByAdminOverrideCheckedValueTo,
+                    )
+                }
             restrictedSwitchPreferenceModel.RestrictionWrapper {
                 content(restrictedSwitchPreferenceModel)
             }
@@ -127,23 +138,31 @@
         fun RestrictionsProviderFactory.RestrictedSwitchWrapper(
             model: SwitchPreferenceModel,
             restrictions: Restrictions,
+            ifBlockedByAdminOverrideCheckedValueTo: Boolean? = null,
             content: @Composable (SwitchPreferenceModel) -> Unit,
         ) {
-            RestrictedSwitchWrapper(model, rememberRestrictedMode(restrictions).value, content)
+            RestrictedSwitchWrapper(
+                model = model,
+                restrictedMode = rememberRestrictedMode(restrictions).value,
+                ifBlockedByAdminOverrideCheckedValueTo = ifBlockedByAdminOverrideCheckedValueTo,
+                content = content,
+            )
         }
 
         fun getSummary(
             context: Context,
-            restrictedModeSupplier: () -> RestrictedMode?,
             summaryIfNoRestricted: () -> String,
-            checked: () -> Boolean?,
+            checkedIfNoRestricted: () -> Boolean?,
+            checkedIfBlockedByAdmin: Boolean? = null,
+            restrictedModeSupplier: () -> RestrictedMode?,
         ): () -> String = {
             when (val restrictedMode = restrictedModeSupplier()) {
                 is NoRestricted -> summaryIfNoRestricted()
                 is BaseUserRestricted ->
                     context.getString(com.android.settingslib.R.string.disabled)
 
-                is BlockedByAdmin -> restrictedMode.getSummary(checked())
+                is BlockedByAdmin ->
+                    restrictedMode.getSummary(checkedIfBlockedByAdmin ?: checkedIfNoRestricted())
                 is BlockedByEcm ->
                     context.getString(com.android.settingslib.R.string.disabled)
 
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt
index bf0ad0b..e736115 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt
@@ -26,9 +26,11 @@
 import androidx.compose.ui.test.performClick
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.RestrictedLockUtils
 import com.android.settingslib.spa.testutils.FakeNavControllerWrapper
 import com.android.settingslib.spaprivileged.R
 import com.android.settingslib.spaprivileged.framework.compose.getPlaceholder
+import com.android.settingslib.spaprivileged.model.enterprise.BlockedByAdminImpl
 import com.android.settingslib.spaprivileged.model.enterprise.NoRestricted
 import com.android.settingslib.spaprivileged.tests.testutils.FakeRestrictionsProvider
 import com.android.settingslib.spaprivileged.tests.testutils.TestAppRecord
@@ -97,6 +99,26 @@
     }
 
     @Test
+    fun summary_whenAllowedButAdminOverrideToNotAllowed() {
+        fakeRestrictionsProvider.restrictedMode =
+            BlockedByAdminImpl(context = context, enforcedAdmin = ENFORCED_ADMIN)
+        val listModel =
+            TestTogglePermissionAppListModel(
+                isAllowed = true,
+                switchifBlockedByAdminOverrideCheckedValueTo = false,
+            )
+
+        val summary = getSummary(listModel)
+
+        assertThat(summary)
+            .isEqualTo(
+                context.getString(
+                    com.android.settingslib.widget.restricted.R.string.disabled_by_admin
+                )
+            )
+    }
+
+    @Test
     fun appListItem_onClick_navigate() {
         val listModel = TestTogglePermissionAppListModel()
         composeTestRule.setContent {
@@ -162,8 +184,9 @@
         const val PACKAGE_NAME = "package.name"
         const val LABEL = "Label"
         const val SUMMARY = "Summary"
-        val APP = ApplicationInfo().apply {
-            packageName = PACKAGE_NAME
-        }
+        val APP = ApplicationInfo().apply { packageName = PACKAGE_NAME }
+        const val RESTRICTION = "restriction"
+        val ENFORCED_ADMIN: RestrictedLockUtils.EnforcedAdmin =
+            RestrictedLockUtils.EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(RESTRICTION)
     }
 }
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt
index b88d1c5..1fd7ecf 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt
@@ -121,7 +121,7 @@
     }
 
     @Test
-    fun whenBlockedByAdmin_disabled() {
+    fun whenBlockedByAdmin_notOverrideChecked() {
         val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
         fakeRestrictionsProvider.restrictedMode = fakeBlockedByAdmin
 
@@ -133,6 +133,18 @@
     }
 
     @Test
+    fun whenBlockedByAdmin_overrideCheckedToFalse() {
+        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
+        fakeRestrictionsProvider.restrictedMode = fakeBlockedByAdmin
+
+        setContent(restrictions, ifBlockedByAdminOverrideCheckedValueTo = false)
+
+        composeTestRule.onNodeWithText(TITLE).assertIsDisplayed().assertIsEnabled()
+        composeTestRule.onNodeWithText(FakeBlockedByAdmin.SUMMARY).assertIsDisplayed()
+        composeTestRule.onNode(isOff()).assertIsDisplayed()
+    }
+
+    @Test
     fun whenBlockedByAdmin_click() {
         val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
         fakeRestrictionsProvider.restrictedMode = fakeBlockedByAdmin
@@ -166,9 +178,16 @@
         assertThat(fakeBlockedByEcm.showRestrictedSettingsDetailsIsCalled).isTrue()
     }
 
-    private fun setContent(restrictions: Restrictions) {
+    private fun setContent(
+        restrictions: Restrictions,
+        ifBlockedByAdminOverrideCheckedValueTo: Boolean? = null,
+    ) {
         composeTestRule.setContent {
-            RestrictedSwitchPreference(switchPreferenceModel, restrictions) { _, _ ->
+            RestrictedSwitchPreference(
+                model = switchPreferenceModel,
+                restrictions = restrictions,
+                ifBlockedByAdminOverrideCheckedValueTo = ifBlockedByAdminOverrideCheckedValueTo,
+            ) { _, _ ->
                 fakeRestrictionsProvider
             }
         }
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt
index 1790313..000743e 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt
@@ -28,6 +28,7 @@
 class TestTogglePermissionAppListModel(
     isAllowed: Boolean? = null,
     private val isChangeable: Boolean = false,
+    override val switchifBlockedByAdminOverrideCheckedValueTo: Boolean? = null,
 ) : TogglePermissionAppListModel<TestAppRecord> {
     override val pageTitleResId = R.string.test_permission_title
     override val switchTitleResId = R.string.test_permission_switch_title
diff --git a/packages/SettingsLib/UsageProgressBarPreference/res/layout/preference_usage_progress_bar.xml b/packages/SettingsLib/UsageProgressBarPreference/res/layout/preference_usage_progress_bar.xml
index ea033a3..7d366f3 100644
--- a/packages/SettingsLib/UsageProgressBarPreference/res/layout/preference_usage_progress_bar.xml
+++ b/packages/SettingsLib/UsageProgressBarPreference/res/layout/preference_usage_progress_bar.xml
@@ -22,9 +22,9 @@
     android:layout_height="wrap_content"
     android:gravity="center_vertical"
     android:orientation="vertical"
-    android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
-    android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:paddingBottom="16dp">
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:paddingBottom="@dimen/settingslib_expressive_space_small1">
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:layout_width="match_parent"
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index 076f82a..89de995 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -178,3 +178,10 @@
     description: "Enable the input routing control in device details and hearing devices dialog."
     bug: "349255906"
 }
+
+flag {
+    name: "hearing_device_set_connection_status_report"
+    namespace: "accessibility"
+    description: "Enable the connection status report for a set of hearing device."
+    bug: "357878944"
+}
diff --git a/packages/SettingsLib/res/drawable/ic_tv_box_internal_speaker.xml b/packages/SettingsLib/res/drawable/ic_tv_box_internal_speaker.xml
new file mode 100644
index 0000000..2a90e05
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_tv_box_internal_speaker.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="?android:attr/textColorPrimary"
+    android:autoMirrored="true">
+    <path android:fillColor="#FFFFFFFF"
+        android:pathData="M14,20.725V18.675Q16.25,18.025 17.625,16.175Q19,14.325 19,11.975Q19,9.625 17.625,7.775Q16.25,5.925 14,5.275V3.225Q17.1,3.925 19.05,6.362Q21,8.8 21,11.975Q21,15.15 19.05,17.587Q17.1,20.025 14,20.725ZM3,15V9H7L12,4V20L7,15ZM14,16V7.95Q15.175,8.5 15.838,9.6Q16.5,10.7 16.5,12Q16.5,13.275 15.838,14.362Q15.175,15.45 14,16ZM10,8.85 L7.85,11H5V13H7.85L10,15.15ZM7.5,12Z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 3225985..656c32d 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Hierdie foon"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Hierdie tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Hierdie rekenaar (intern)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dokluidspreker"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Eksterne toestel"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Gekoppel deur ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Gekoppel deur eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV-verstek"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI-uitset"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Interne luidsprekers"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Kan nie koppel nie. Skakel toestel af en weer aan"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedrade oudiotoestel"</string>
     <string name="help_label" msgid="3528360748637781274">"Hulp en terugvoer"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 34f37b4..3757d90 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ይህ ስልክ"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ይህ ጡባዊ"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ይህ ኮምፒውተር (ውስጣዊ)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"የመትከያ ድምፅ ማውጫ"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"የውጭ መሣሪያ"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI ኢኤአርሲ"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"በኤአርሲ በኩል ተገናኝቷል"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"በኢኤአርሲ በኩል ተገናኝቷል"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"የቲቪ ነባሪ"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"የHDMI ውጤት"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"ውስጣዊ ድምፅ ማውጫዎች"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"መገናኘት ላይ ችግር። መሳሪያውን ያጥፉት እና እንደገና ያብሩት"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ባለገመድ የኦዲዮ መሣሪያ"</string>
     <string name="help_label" msgid="3528360748637781274">"እገዛ እና ግብረመልስ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 2ea1486..838b974 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"هذا الهاتف"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"هذا الجهاز اللوحي"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"هذا الكمبيوتر (داخلي)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"مكبّر صوت بقاعدة إرساء"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"جهاز خارجي"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"‏متّصل من خلال ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"‏متّصل من خلال eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"الجهاز التلقائي لإخراج صوت التلفزيون"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"‏إخراج الصوت من خلال HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"مكبّرات الصوت الداخلية"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"حدثت مشكلة أثناء الاتصال. يُرجى إيقاف الجهاز ثم إعادة تشغيله."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"جهاز سماعي سلكي"</string>
     <string name="help_label" msgid="3528360748637781274">"المساعدة والملاحظات"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 432d443..d00e7ee 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"এই ফ’নটো"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"এই টেবলেটটো"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"এই কম্পিউটাৰ (অভ্যন্তৰীণ)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ড’ক স্পীকাৰ"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"বাহ্যিক ডিভাইচ"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARCৰ জৰিয়তে সংযুক্ত"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARCৰ জৰিয়তে সংযুক্ত"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"টিভি ডিফ’ল্ট"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI আউটপুট"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"অভ্যন্তৰীণ স্পীকাৰ"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"সংযোগ হোৱাত সমস্যা হৈছে। ডিভাইচটো অফ কৰি পুনৰ অন কৰক"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"তাঁৰযুক্ত অডিঅ’ ডিভাইচ"</string>
     <string name="help_label" msgid="3528360748637781274">"সহায় আৰু মতামত"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 330532e..3607a97 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Bu telefon"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Bu planşet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Bu kompüter (daxili)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dok dinamiki"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Xarici cihaz"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Chrome-da Tətbiqin İşləmə Müddəti vasitəsilə qoşulub"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC vasitəsilə qoşulub"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV defoltu"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI çıxışı"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Daxili dinamiklər"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Qoşulmaqla bağlı problem. Cihazı deaktiv edin, sonra yenidən aktiv edin"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio cihaz"</string>
     <string name="help_label" msgid="3528360748637781274">"Yardım və rəy"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 4dfd253..94f4bd0 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ovaj telefon"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ovaj tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ovaj računar (interno)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvučnik bazne stanice"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Spoljni uređaj"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Povezano preko ARC-a"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Povezano preko eARC-a"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Podrazumevana vrednost za TV"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI izlaz"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Unutrašnji zvučnici"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem pri povezivanju. Isključite uređaj, pa ga ponovo uključite"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string>
     <string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index de25460..1903a30 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Гэты тэлефон"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Гэты планшэт"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Гэты камп’ютар (унутраны)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Дынамік док-станцыі"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Знешняя прылада"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Падключана праз ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Падключана праз eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Стандартны аўдыявыхад тэлевізара"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Выхад HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Унутраныя дынамікі"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Праблема з падключэннем. Выключыце і зноў уключыце прыладу"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Правадная аўдыяпрылада"</string>
     <string name="help_label" msgid="3528360748637781274">"Даведка і водгукі"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 47ce37c..da1561a 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Този телефон"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Този таблет"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Този компютър (вграден)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Високоговорител докинг станция"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Външно устройство"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Свързано посредством ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Свързано посредством eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Стандартното за телевизора"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI изход"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Вградени високоговорители"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"При свързването възникна проблем. Изключете устройството и го включете отново"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Аудиоустройство с кабел"</string>
     <string name="help_label" msgid="3528360748637781274">"Помощ и отзиви"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 3b77cfd..90e7e60 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"এই ফোন"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"এই ট্যাবলেট"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"এই কম্পিউটার (ইন্টার্নাল)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ডক স্পিকার"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"এক্সটার্নাল ডিভাইস"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC-এর মাধ্যমে কানেক্ট করা হয়েছে"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC-এর মাধ্যমে কানেক্ট করা হয়েছে"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"টিভির ডিফল্ট সেটিং"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI আউটপুট"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"ইন্টার্নাল স্পিকার"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"কানেক্ট করতে সমস্যা হচ্ছে। ডিভাইস বন্ধ করে আবার চালু করুন"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ওয়্যার অডিও ডিভাইস"</string>
     <string name="help_label" msgid="3528360748637781274">"সহায়তা ও মতামত"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 65eb681..2ac15c4 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ovaj telefon"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ovaj tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ovaj računar (interno)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvučnik priključne stanice"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Vanjski uređaj"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Povezano je putem ARC-a"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Povezano je putem eARC-a"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Zadano za TV"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI izlaz"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Interni zvučnici"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Došlo je do problema prilikom povezivanja. Isključite, pa ponovo uključite uređaj"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string>
     <string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index a7c3faf..dcc614f 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Aquest telèfon"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Aquesta tauleta"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Aquest ordinador (intern)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Base d\'altaveu"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositiu extern"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Connectat mitjançant ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Connectat mitjançant eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Televisor predeterminat"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Sortida HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Altaveus interns"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Hi ha hagut un problema amb la connexió. Apaga el dispositiu i torna\'l a encendre."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositiu d\'àudio amb cable"</string>
     <string name="help_label" msgid="3528360748637781274">"Ajuda i suggeriments"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 832d320..3d45732 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Tento telefon"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Tento tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Tento počítač (interní)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Reproduktor doku"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externí zařízení"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Připojeno přes ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Připojeno přes eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Výchozí nastavení televize"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Výstup HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Interní reproduktory"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problém s připojením. Vypněte zařízení a znovu jej zapněte"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kabelové audiozařízení"</string>
     <string name="help_label" msgid="3528360748637781274">"Nápověda a zpětná vazba"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 708d5df..7ed51e4 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Denne telefon"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Denne tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Denne computer (intern)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dockhøjttaler"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ekstern enhed"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Forbundet via ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Forbundet via eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Standardindstillinger for fjernsyn"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI-udgang"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Interne højttalere"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Der kunne ikke oprettes forbindelse. Sluk og tænd enheden"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhed med ledning"</string>
     <string name="help_label" msgid="3528360748637781274">"Hjælp og feedback"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 069201a..ee62344 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Dieses Smartphone"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Dieses Tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Dieser Computer (intern)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock-Lautsprecher"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externes Gerät"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Per ARC verbunden"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Per eARC verbunden"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Standardeinstellung: Fernseher"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI-Ausgang"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Interne Lautsprecher"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Verbindung kann nicht hergestellt werden. Schalte das Gerät aus und wieder ein."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Netzbetriebenes Audiogerät"</string>
     <string name="help_label" msgid="3528360748637781274">"Hilfe und Feedback"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 8577a9a..ec3949c 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Αυτό το τηλέφωνο"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Αυτό το tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Αυτός ο υπολογιστής (εσωτερ.)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Ηχείο βάσης σύνδεσης"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Εξωτερική συσκευή"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Συνδέθηκε μέσω ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Συνδέθηκε μέσω eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Προεπιλογή τηλεόρασης"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Έξοδος HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Εσωτερικά ηχεία"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Πρόβλημα κατά τη σύνδεση. Απενεργοποιήστε τη συσκευή και ενεργοποιήστε την ξανά"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Ενσύρματη συσκευή ήχου"</string>
     <string name="help_label" msgid="3528360748637781274">"Βοήθεια και σχόλια"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index f9d2f08..bb1efc4 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"This phone"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"This tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"This computer (internal)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Connected via ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Connected via eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV default"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI output"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Internal speakers"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
     <string name="help_label" msgid="3528360748637781274">"Help and feedback"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 2cf98ef..6d1cce6 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"This phone"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"This tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"This computer (internal)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"External Device"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Connected via ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Connected via eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV default"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI output"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Internal speakers"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off &amp; back on"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
     <string name="help_label" msgid="3528360748637781274">"Help and feedback"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index f9d2f08..bb1efc4 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"This phone"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"This tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"This computer (internal)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Connected via ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Connected via eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV default"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI output"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Internal speakers"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
     <string name="help_label" msgid="3528360748637781274">"Help and feedback"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index f9d2f08..bb1efc4 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"This phone"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"This tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"This computer (internal)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Connected via ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Connected via eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV default"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI output"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Internal speakers"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
     <string name="help_label" msgid="3528360748637781274">"Help and feedback"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index a4834d8..f5fd368 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este teléfono"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Esta tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Esta computadora (interna)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Bocina de la estación de carga"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Se estableció conexión con un cable ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Se estableció conexión con un cable eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Configuración predeterminada de la TV"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Salida de HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Bocinas internas"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Error al establecer la conexión. Apaga el dispositivo y vuelve a encenderlo."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
     <string name="help_label" msgid="3528360748637781274">"Ayuda y comentarios"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 1792fd1..b78d9fd 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este teléfono"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Esta tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Este ordenador (interno)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altavoz de la base"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Conectado mediante ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Conectado mediante eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Predeterminada de la televisión"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Salida HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Altavoces internos"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"No se ha podido conectar; reinicia el dispositivo"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
     <string name="help_label" msgid="3528360748637781274">"Ayuda y comentarios"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 5411d0b..078e038 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"See telefon"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"See tahvelarvuti"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"See arvuti (sisemine)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Doki kõlar"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Väline seade"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Ühendatud ARC-i kaudu"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Ühendatud eARC-i kaudu"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Teleri vaikeväljund"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI-väljund"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Sisemised kõlarid"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem ühendamisel. Lülitage seade välja ja uuesti sisse"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Juhtmega heliseade"</string>
     <string name="help_label" msgid="3528360748637781274">"Abi ja tagasiside"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 090d99d..cc60fd5 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Telefono hau"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Tableta hau"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ordenagailu hau (barnekoa)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Oinarri bozgorailuduna"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Kanpoko gailua"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC bidez konektatuta"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC bidez konektatuta"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Telebistaren audio-erreproduzigailu lehenetsia"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI irteera"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Barneko bozgorailuak"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Arazo bat izan da konektatzean. Itzali gailua eta pitz ezazu berriro."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio-gailu kableduna"</string>
     <string name="help_label" msgid="3528360748637781274">"Laguntza eta iritziak"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index c350175..61b0b0f7 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"این تلفن"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"این رایانه لوحی"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"این رایانه (داخلی)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"بلندگوی پایه اتصال"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"دستگاه خارجی"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"‏متصل ازطریق ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"‏متصل ازطریق eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"پیش‌فرض تلویزیون"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"‏خروجی HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"بلندگوهای داخلی"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"مشکل در اتصال. دستگاه را خاموش و دوباره روشن کنید"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"دستگاه صوتی سیمی"</string>
     <string name="help_label" msgid="3528360748637781274">"راهنما و بازخورد"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 18a84b5..683c3c7 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Tämä puhelin"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Tämä tabletti"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Tämä tietokone (sisäinen)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Telinekaiutin"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ulkoinen laite"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Yhdistetty ARC:n kautta"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Yhdistetty eARC:n kautta"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV:n oletusasetus"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI-toisto"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Sisäiset kaiuttimet"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Yhteysvirhe. Sammuta laite ja käynnistä se uudelleen."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Langallinen äänilaite"</string>
     <string name="help_label" msgid="3528360748637781274">"Ohjeet ja palaute"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 066244a..29eaee3 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ce téléphone"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Cette tablette"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Cet ordinateur (interne)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Haut-parleur du socle"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Appareil externe"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Connecté par ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Connecté par eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Sortie audio par défaut de la télévision"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Sortie HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Haut-parleurs internes"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteignez et rallumez l\'appareil"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio à câble"</string>
     <string name="help_label" msgid="3528360748637781274">"Aide et commentaires"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 84c2f15..04a212c 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ce téléphone"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Cette tablette"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Cet ordinateur (interne)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Haut-parleur station d\'accueil"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Appareil externe"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Connecté via ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Connecté via eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Sortie par défaut de la TV"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Sortie HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Haut-parleurs internes"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteignez l\'appareil, puis rallumez-le"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio filaire"</string>
     <string name="help_label" msgid="3528360748637781274">"Aide et commentaires"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index d15b6e2..d5be2ce 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este teléfono"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Esta tableta"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Este ordenador (interno)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altofalante da base"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Conectado mediante ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Conectado mediante eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Opción predeterminada da televisión"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Saída HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Altofalantes internos"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Produciuse un problema coa conexión. Apaga e acende o dispositivo."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
     <string name="help_label" msgid="3528360748637781274">"Axuda e comentarios"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 5fd187f..54094cb 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"આ ફોન"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"આ ટૅબ્લેટ"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"આ કમ્પ્યૂટર (આંતરિક)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ડૉક સ્પીકર"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"બહારનું ડિવાઇસ"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC મારફતે કનેક્ટેડ"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC મારફતે કનેક્ટેડ"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"ડિવાઇસનું ડિફૉલ્ટ ઑડિયો આઉટપુટ, ટીવી"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI આઉટપુટ"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"આંતરિક સ્પીકર"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"કનેક્ટ કરવામાં સમસ્યા આવી રહી છે. ડિવાઇસને બંધ કરીને ફરી ચાલુ કરો"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"વાયરવાળો ઑડિયો ડિવાઇસ"</string>
     <string name="help_label" msgid="3528360748637781274">"સહાય અને પ્રતિસાદ"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index fa0716e..1654b05 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"यह फ़ोन"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"यह टैबलेट"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"यह कंप्यूटर (इंटरनल)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डॉक स्पीकर"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाहरी डिवाइस"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"एचडीएमआई eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC से कनेक्ट किए गए डिवाइस"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC से कनेक्ट किए गए डिवाइस"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"टीवी की डिफ़ॉल्ट सेटिंग"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"एचडीएमआई आउटपुट"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"इंटरनल स्पीकर"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्ट करने में समस्या हो रही है. डिवाइस को बंद करके चालू करें"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर वाला ऑडियो डिवाइस"</string>
     <string name="help_label" msgid="3528360748637781274">"सहायता और सुझाव"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 8ad5c9d..f7552b2 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ovaj telefon"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ovaj tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ovo računalo (interno)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvučnik priključne stanice"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Vanjski uređaj"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Povezano putem ARC-a"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Povezano putem eARC-a"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Zadano za TV"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI izlaz"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Unutarnji zvučnici"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem s povezivanjem. Isključite i ponovo uključite uređaj"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audiouređaj"</string>
     <string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 18c6ea3..2e5d6b5 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ez a telefon"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ez a táblagép"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ez a számítógép (belső)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dokkhangszóró"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Külső eszköz"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Csatlakoztatva ARC-n keresztül"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Csatlakoztatva eARC-n keresztül"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Tévé alapértelmezett eszköze"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI-kimenet"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Belső hangszórók"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sikertelen csatlakozás. Kapcsolja ki az eszközt, majd kapcsolja be újra."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vezetékes audioeszköz"</string>
     <string name="help_label" msgid="3528360748637781274">"Súgó és visszajelzés"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 593479a..cc88919 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Այս հեռախոսը"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Այս պլանշետը"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Այս համակարգիչը (ներքին)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Դոկ-կայանով բարձրախոս"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Արտաքին սարք"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Միացված է ARC-ի միջոցով"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Միացված է eARC-ի միջոցով"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Հեռուստացույցի կանխադրված կարգավորումներ"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI ելք"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Ներքին բարձրախոսներ"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Կապի խնդիր կա: Սարքն անջատեք և նորից միացրեք:"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Լարով աուդիո սարք"</string>
     <string name="help_label" msgid="3528360748637781274">"Օգնություն և հետադարձ կապ"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 6522e22..0f01dea 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ponsel ini"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Tablet ini"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Komputer ini (internal)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Speaker dok"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Perangkat Eksternal"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Terhubung melalui ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Terhubung melalui eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV sebagai default"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Output HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Speaker internal"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ada masalah saat menghubungkan. Nonaktifkan perangkat &amp; aktifkan kembali"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Perangkat audio berkabel"</string>
     <string name="help_label" msgid="3528360748637781274">"Bantuan &amp; masukan"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 4a10fb3..c163cc2 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Þessi sími"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Þessi spjaldtölva"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Þessi tölva (innbyggður)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Hátalaradokka"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ytra tæki"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Tengt með ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Tengt með eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Sjálfgefið í sjónvarpi"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI-úttak"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Innri hátalarar"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Vandamál í tengingu. Slökktu og kveiktu á tækinu"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Snúrutengt hljómtæki"</string>
     <string name="help_label" msgid="3528360748637781274">"Hjálp og ábendingar"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 21f78dd..c7eb70c 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Questo smartphone"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Questo tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Questo computer (interno)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Base con altoparlante"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo esterno"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"eARC HDMI"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Connessione tramite ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Connessione tramite eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV predefinita"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Uscita HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Altoparlanti interni"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema di connessione. Spegni e riaccendi il dispositivo"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo audio cablato"</string>
     <string name="help_label" msgid="3528360748637781274">"Guida e feedback"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 3b28bd2..c884362 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"הטלפון הזה"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"הטאבלט הזה"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"המחשב הזה (פנימי)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"רמקול של אביזר העגינה"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"מכשיר חיצוני"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"‏חיבור דרך ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"‏חיבור דרך eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"ברירת המחדל של הטלוויזיה"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"‏פלט HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"רמקולים פנימיים"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"יש בעיה בחיבור. עליך לכבות את המכשיר ולהפעיל אותו מחדש"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"התקן אודיו חוטי"</string>
     <string name="help_label" msgid="3528360748637781274">"עזרה ומשוב"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index a826810..bd781be 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"このデバイス"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"このタブレット"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"このパソコン(内蔵)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ホルダー スピーカー"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部デバイス"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC 経由で接続済み"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC 経由で接続済み"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"テレビのデフォルト"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI 出力"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"内蔵スピーカー"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"接続エラーです。デバイスを OFF にしてから ON に戻してください"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線オーディオ デバイス"</string>
     <string name="help_label" msgid="3528360748637781274">"ヘルプとフィードバック"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index f321371..89ef86e 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ეს ტელეფონი"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ამ ტაბლეტზე"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ეს კომპიუტერი (შიდა)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"სამაგრის დინამიკი"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"გარე მოწყობილობა"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"დაკავშირებულია ARC-ის მეშვეობით"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"დაკავშირებულია eARC-ის მეშვეობით"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"ტელევიზორის ნაგულისხმევი"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"გამომავალი HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"შიდა დინამიკები"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"დაკავშირებისას წარმოიქმნა პრობლემა. გამორთეთ და კვლავ ჩართეთ მოწყობილობა"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"სადენიანი აუდიო მოწყობილობა"</string>
     <string name="help_label" msgid="3528360748637781274">"დახმარება და გამოხმაურება"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 85b86d4..fe4f1cd 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Осы телефон"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Осы планшет"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Осы компьютер (ішкі)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Динамигі бар қондыру станциясы"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Сыртқы құрылғы"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC арқылы жалғанған."</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC арқылы жалғанған."</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Теледидардың әдепкі шығысы"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI шығыс интерфейсі"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Ішкі динамиктер"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Байланыс орнату қатесі шығуып жатыр. Құрылғыны өшіріп, қайта қосыңыз."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Сымды аудио құрылғысы"</string>
     <string name="help_label" msgid="3528360748637781274">"Анықтама және пікір"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 12d35cf..36421c9 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ទូរសព្ទនេះ"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ថេប្លេតនេះ"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"កុំព្យូទ័រនេះ (ខាងក្នុង)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ឧបាល័រជើងទម្រ"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ឧបករណ៍ខាងក្រៅ"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"បានភ្ជាប់តាមរយៈ ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"បានភ្ជាប់តាមរយៈ eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"លំនាំដើម​ទូរទស្សន៍"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"ធាតុចេញ HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"ឧបករណ៍បំពងសំឡេងខាងក្នុង"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"មាន​បញ្ហា​ក្នុងការ​ភ្ជាប់។ បិទ រួច​បើក​ឧបករណ៍​វិញ"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ឧបករណ៍​សំឡេងប្រើខ្សែ"</string>
     <string name="help_label" msgid="3528360748637781274">"ជំនួយ និងមតិកែលម្អ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index d95846f..78f0a37 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ಈ ಫೋನ್"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ಈ ಟ್ಯಾಬ್ಲೆಟ್"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ಈ ಕಂಪ್ಯೂಟರ್ (ಆಂತರಿಕ)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ಡಾಕ್ ಸ್ಪೀಕರ್"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ಬಾಹ್ಯ ಸಾಧನ"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC ಮೂಲಕ ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC ಮೂಲಕ ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"ಟಿವಿ ಡೀಫಾಲ್ಟ್"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI ಔಟ್‌‌ಪುಟ್"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"ಆಂತರಿಕ ಸ್ಪೀಕರ್‌ಗಳು"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ಕನೆಕ್ಟ್ ಮಾಡುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ ಸಾಧನವನ್ನು ಆಫ್ ಮಾಡಿ ಹಾಗೂ ನಂತರ ಪುನಃ ಆನ್ ಮಾಡಿ"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ವೈರ್ ಹೊಂದಿರುವ ಆಡಿಯೋ ಸಾಧನ"</string>
     <string name="help_label" msgid="3528360748637781274">"ಸಹಾಯ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index f82a6a6..9ce92221 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"이 휴대전화"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"이 태블릿"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"이 컴퓨터(내부)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"도크 스피커"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"외부 기기"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC를 통해 연결됨"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC를 통해 연결됨"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV 기본값"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI 출력"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"내부 스피커"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"연결 중에 문제가 발생했습니다. 기기를 껐다가 다시 켜 보세요."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"유선 오디오 기기"</string>
     <string name="help_label" msgid="3528360748637781274">"고객센터"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index ff63c19..86eb12d 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ушул телефон"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ушул планшет"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Бул компьютер (ички)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Док бекеттин динамиги"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Тышкы түзмөк"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC аркылуу туташты"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC аркылуу туташты"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Cыналгыдагы демейки түзмөк"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI аудио түзмөгү"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Ички динамиктер"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Туташууда маселе келип чыкты. Түзмөктү өчүрүп, кайра күйгүзүп көрүңүз"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Зымдуу аудио түзмөк"</string>
     <string name="help_label" msgid="3528360748637781274">"Жардам/Пикир билдирүү"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 36d2ccf..2d800c5 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ໂທລະສັບນີ້"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ແທັບເລັດນີ້"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ຄອມພິວເຕີນີ້ (ພາຍໃນ)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ແທ່ນວາງລຳໂພງ"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ອຸປະກອນພາຍນອກ"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ເຊື່ອມຕໍ່ຜ່ານ ARC ແລ້ວ"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"ເຊື່ອມຕໍ່ຜ່ານ eARC ແລ້ວ"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"ຄ່າເລີ່ມຕົ້ນສຳລັບໂທລະທັດ"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"ເອົ້າພຸດ HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"ລຳໂພງຂອງເຄື່ອງ"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ເກີດບັນຫາໃນການເຊື່ອມຕໍ່. ປິດອຸປະກອນແລ້ວເປີດກັບຄືນມາໃໝ່"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ອຸປະກອນສຽງແບບມີສາຍ"</string>
     <string name="help_label" msgid="3528360748637781274">"ຊ່ວຍເຫຼືອ ແລະ ຕິຊົມ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 5b20db3..08bf303 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Šis telefonas"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Šis planšetinis kompiuteris"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Šis kompiuteris (vidinis)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Doko garsiakalbis"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Išorinis įrenginys"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI „eARC“"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Prisijungta per ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Prisijungta per „eARC“"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV numatytoji išvestis"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI išvestis"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Vidiniai garsiakalbiai"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Prisijungiant kilo problema. Išjunkite įrenginį ir vėl jį įjunkite"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Laidinis garso įrenginys"</string>
     <string name="help_label" msgid="3528360748637781274">"Pagalba ir atsiliepimai"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 620318a..e0ba424 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Šis tālrunis"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Šis planšetdators"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Šī datora iekšējais skaļrunis"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Doka skaļrunis"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ārēja ierīce"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Savienojums izveidots, izmantojot ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Savienojums izveidots, izmantojot eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Noklusējuma iestatījums televizorā"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI izvade"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Iekšējie skaļruņi"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Radās problēma ar savienojuma izveidi. Izslēdziet un atkal ieslēdziet ierīci."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vadu audioierīce"</string>
     <string name="help_label" msgid="3528360748637781274">"Palīdzība un atsauksmes"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 0331ece..86312aa 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -359,7 +359,7 @@
     <string name="enable_terminal_summary" msgid="2481074834856064500">"Овозможи апликација на терминал што овозможува локален пристап кон школка."</string>
     <string name="enable_linux_terminal_title" msgid="5076044866895670637">"Програмерска околина на Linux"</string>
     <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Експериментално) Вклучете го Linux-терминалот на Android"</string>
-    <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Ако оневозможите, податоците за Linux-терминалот ќе се избришат"</string>
+    <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Ако го оневозможите, податоците за Linux-терминалот ќе се избришат"</string>
     <string name="hdcp_checking_title" msgid="3155692785074095986">"Проверка со HDCP"</string>
     <string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Постави однесување на проверка на HDCP"</string>
     <string name="debug_debugging_category" msgid="535341063709248842">"Отстранување грешки"</string>
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Овој телефон"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Овој таблет"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Овој компјуер (внатрешен)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Док со звучник"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Надворешен уред"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Поврзано преку ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Поврзано преку eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Стандарден излез на телевизор"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Излез за HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Внатрешни звучници"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем со поврзување. Исклучете го уредот и повторно вклучете го"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичен аудиоуред"</string>
     <string name="help_label" msgid="3528360748637781274">"Помош и повратни информации"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index aaebe4c..04596d2 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ഈ ഫോൺ"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ഈ ടാബ്‌ലെറ്റ്"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ഈ കമ്പ്യൂട്ടർ (ഇന്റേണൽ)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ഡോക്ക് സ്‌പീക്കർ"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ബാഹ്യ ഉപകരണം"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC വഴി കണക്റ്റ് ചെയ്തിരിക്കുന്നു"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC വഴി കണക്റ്റ് ചെയ്തിരിക്കുന്നു"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"ടിവി ഡിഫോൾട്ട്"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI ഔട്ട്പുട്ട്"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"ആന്തരിക സ്‌പീക്കറുകൾ"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"കണക്‌റ്റ് ചെയ്യുന്നതിൽ പ്രശ്‌നമുണ്ടായി. ഉപകരണം ഓഫാക്കി വീണ്ടും ഓണാക്കുക"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"വയർ മുഖേന ബന്ധിപ്പിച്ച ഓഡിയോ ഉപകരണം"</string>
     <string name="help_label" msgid="3528360748637781274">"സഹായവും ഫീഡ്‌ബാക്കും"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index fb2b729..a4d5a8f 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Энэ утас"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Энэ таблет"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Энэ компьютер (дотоод)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Суурилуулагчийн чанга яригч"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Гадаад төхөөрөмж"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC-р холбогдсон"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC-р холбогдсон"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"ТВ-ийн өгөгдмөл"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI гаралт"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Дотоод чанга яригч"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Холбогдоход асуудал гарлаа. Төхөөрөмжийг унтраагаад дахин асаана уу"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Утастай аудио төхөөрөмж"</string>
     <string name="help_label" msgid="3528360748637781274">"Тусламж, санал хүсэлт"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 023a2e4..0ac6b84 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"हा फोन"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"हा टॅबलेट"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"हा काँप्युटर (अंतर्गत)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डॉक स्पीकर"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाह्य डिव्हाइस"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC द्वारे कनेक्ट केलेली"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC द्वारे कनेक्ट केलेली"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"टीव्ही डीफॉल्ट"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI आउटपुट"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"अंतर्गत स्पीकर"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्‍ट करण्‍यात समस्‍या आली. डिव्हाइस बंद करा आणि नंतर सुरू करा"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर असलेले ऑडिओ डिव्हाइस"</string>
     <string name="help_label" msgid="3528360748637781274">"मदत आणि फीडबॅक"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 4212eb4..888eca2 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Telefon ini"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Tablet ini"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Komputer ini (dalaman)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Pembesar suara dok"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Peranti Luar"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Disambungkan melalui ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Disambungkan melalui eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Tetapan lalai TV"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Output HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Pembesar suara dalaman"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Masalah penyambungan. Matikan &amp; hidupkan kembali peranti"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Peranti audio berwayar"</string>
     <string name="help_label" msgid="3528360748637781274">"Bantuan &amp; maklum balas"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index df13e6c..0ce7381 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ဤဖုန်း"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ဤတက်ဘလက်"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ဤကွန်ပျူတာ (စက်တွင်း)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"အထိုင် စပီကာ"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ပြင်ပစက်"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC မှတစ်ဆင့် ချိတ်ဆက်ထားသည်"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC မှတစ်ဆင့် ချိတ်ဆက်ထားသည်"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV မူရင်း"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI အထွက်"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"စက်ရှိ စပီကာများ"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ချိတ်ဆက်ရာတွင် ပြဿနာရှိပါသည်။ စက်ကိုပိတ်ပြီး ပြန်ဖွင့်ပါ"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ကြိုးတပ် အသံစက်ပစ္စည်း"</string>
     <string name="help_label" msgid="3528360748637781274">"အကူအညီနှင့် အကြံပြုချက်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 8126663..72bce76 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Denne telefonen"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Dette nettbrettet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Denne datamaskinen (intern)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dokkhøyttaler"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ekstern enhet"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Tilkoblet via ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Tilkoblet via eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV-ens standardinnstilling"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI-utgang"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Interne høyttalere"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Tilkoblingsproblemer. Slå enheten av og på igjen"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhet med kabel"</string>
     <string name="help_label" msgid="3528360748637781274">"Hjelp og tilbakemelding"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index a233622..cab816f 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"यो फोन"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"यो ट्याब्लेट"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"यो कम्प्युटर (आन्तरिक)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डक स्पिकर"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाह्य डिभाइस"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC मार्फत कनेक्ट गरिएका"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC मार्फत कनेक्ट गरिएका"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"टिभीको डिफल्ट अडियो आउटपुट"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI आउटपुट"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"आन्तरिक स्पिकरहरू"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"जोड्ने क्रममा समस्या भयो। यन्त्रलाई निष्क्रिय पारेर फेरि अन गर्नुहोस्"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"तारयुक्त अडियो यन्त्र"</string>
     <string name="help_label" msgid="3528360748637781274">"मद्दत र प्रतिक्रिया"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 551097d..22b320d 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Deze telefoon"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Deze tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Deze computer (intern)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dockspeaker"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Extern apparaat"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Verbonden via ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Verbonden via eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Tv-standaard"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI-uitvoer"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Interne speakers"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem bij verbinding maken. Zet het apparaat uit en weer aan."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedraad audioapparaat"</string>
     <string name="help_label" msgid="3528360748637781274">"Hulp en feedback"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 790acff..b8a73f7 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ଏହି ଫୋନ"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ଏହି ଟାବଲେଟ"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ଏହି କମ୍ପ୍ୟୁଟର (ଇଣ୍ଟର୍ନଲ)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ଡକ ସ୍ପିକର"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ଏକ୍ସଟର୍ନଲ ଡିଭାଇସ"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC ମାଧ୍ୟମରେ କନେକ୍ଟ କରାଯାଇଛି"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC ମାଧ୍ୟମରେ କନେକ୍ଟ କରାଯାଇଛି"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"ଟିଭିର ଡିଫଲ୍ଟ ଅଡିଓ ଆଉଟପୁଟ"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI ଆଉଟପୁଟ"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"ଇଣ୍ଟର୍ନଲ ସ୍ପିକର"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ସଂଯୋଗ କରିବାରେ ସମସ୍ୟା ହେଉଛି। ଡିଭାଇସ୍ ବନ୍ଦ କରି ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ତାରଯୁକ୍ତ ଅଡିଓ ଡିଭାଇସ୍"</string>
     <string name="help_label" msgid="3528360748637781274">"ସାହାଯ୍ୟ ଓ ମତାମତ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index c20e0d8..77eb146 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ਇਹ ਫ਼ੋਨ"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ਇਹ ਟੈਬਲੈੱਟ"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ਇਸ ਕੰਪਿਊਟਰ \'ਤੇ (ਅੰਦਰੂਨੀ)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ਡੌਕ ਸਪੀਕਰ"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ਬਾਹਰੀ ਡੀਵਾਈਸ"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤੇ ਗਏ ਡੀਵਾਈਸ"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤੇ ਗਏ ਡੀਵਾਈਸ"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"ਟੀਵੀ ਦਾ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਆਊਟਪੁੱਟ"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI ਆਊਟਪੁੱਟ"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"ਅੰਦਰੂਨੀ ਸਪੀਕਰ"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ਕਨੈਕਟ ਕਰਨ ਵਿੱਚ ਸਮੱਸਿਆ ਆਈ। ਡੀਵਾਈਸ ਨੂੰ ਬੰਦ ਕਰਕੇ ਵਾਪਸ ਚਾਲੂ ਕਰੋ"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ਤਾਰ ਵਾਲਾ ਆਡੀਓ ਡੀਵਾਈਸ"</string>
     <string name="help_label" msgid="3528360748637781274">"ਮਦਦ ਅਤੇ ਵਿਚਾਰ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index f6ab8a7..e5cca9c 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ten telefon"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ten tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ten komputer (wewnętrzny)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Głośnik ze stacją dokującą"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Urządzenie zewnętrzne"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Połączono przez ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Połączono przez eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Ustawienie domyślne telewizora"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Wyjście HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Głośniki wewnętrzne"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem z połączeniem. Wyłącz i ponownie włącz urządzenie"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Przewodowe urządzenie audio"</string>
     <string name="help_label" msgid="3528360748637781274">"Pomoc i opinie"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index dedc65c..a879f17 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este telefone"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Este tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Este computador (interno)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Alto-falante da base"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Conectado via ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Conectado via eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Padrão da TV"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Saída HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Alto-falantes internos"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ocorreu um problema na conexão. Desligue o dispositivo e ligue-o novamente"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fio"</string>
     <string name="help_label" msgid="3528360748637781274">"Ajuda e feedback"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index f1ac88b..3ae270e 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este telemóvel"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Este tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Este computador (interno)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altifalante estação carregamento"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Ligado através de ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Ligado através de eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Predefinição da TV"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Saída HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Altifalantes internos"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema ao ligar. Desligue e volte a ligar o dispositivo."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fios"</string>
     <string name="help_label" msgid="3528360748637781274">"Ajuda e feedback"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index dedc65c..a879f17 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este telefone"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Este tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Este computador (interno)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Alto-falante da base"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Conectado via ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Conectado via eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Padrão da TV"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Saída HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Alto-falantes internos"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ocorreu um problema na conexão. Desligue o dispositivo e ligue-o novamente"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fio"</string>
     <string name="help_label" msgid="3528360748637781274">"Ajuda e feedback"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index cafb788..1fe3651 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Acest telefon"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Această tabletă"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Acest computer (intern)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Difuzorul dispozitivului de andocare"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispozitiv extern"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Conectat prin ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Conectat prin eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Prestabilit pentru televizor"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Ieșire HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Difuzoare interne"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problemă la conectare. Oprește și repornește dispozitivul."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispozitiv audio cu fir"</string>
     <string name="help_label" msgid="3528360748637781274">"Ajutor și feedback"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 951f3a0..f8389ba 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Этот смартфон"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Этот планшет"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Встроенное"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Колонка с док-станцией"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Внешнее устройство"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Подключено через ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Подключено через eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Стандартный выход на телевизоре"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Выход HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Внутренние динамики"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ошибка подключения. Выключите и снова включите устройство."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Проводное аудиоустройство"</string>
     <string name="help_label" msgid="3528360748637781274">"Справка/отзыв"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 8427064..07ce339 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"මෙම දුරකථනය"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"මෙම ටැබ්ලටය"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"මෙම පරිගණකය (අභ්‍යන්තර)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ඩොක් ස්පීකරය"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"බාහිර උපාංගය"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC හරහා සම්බන්ධ කර ඇත"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC හරහා සම්බන්ධ කර ඇත"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"රූපවාහිනී පෙරනිමිය"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI ප්‍රතිදානය"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"අභ්‍යන්තර ස්පීකර්"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"සම්බන්ධ කිරීමේ ගැටලුවකි උපාංගය ක්‍රියාවිරහිත කර &amp; ආපසු ක්‍රියාත්මක කරන්න"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"රැහැන්ගත කළ ඕඩියෝ උපාංගය"</string>
     <string name="help_label" msgid="3528360748637781274">"උදවු &amp; ප්‍රතිපෝෂණ"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index aca07e5..2a24497 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Tento telefón"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Tento tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Tento počítač (interný)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Reproduktor doku"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externé zariadenie"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Pripojené prostredníctvom rozhrania ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Pripojené prostredníctvom rozhrania eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Predvolené nastavenie televízora"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Výstup HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Interné reproduktory"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Pri pripájaní sa vyskytol problém. Zariadenie vypnite a znova zapnite."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio zariadenie s káblom"</string>
     <string name="help_label" msgid="3528360748637781274">"Pomocník a spätná väzba"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 00d93a6..81f3063 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ta telefon"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ta tablični računalnik"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ta računalnik (notranji)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvočnik nosilca"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Zunanja naprava"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Povezano prek zvočnega kanala ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Povezano prek zvočnega kanala eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Privzeti izhod televizorja"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Izhod HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Notranji zvočniki"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Težava pri povezovanju. Napravo izklopite in znova vklopite."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žična zvočna naprava"</string>
     <string name="help_label" msgid="3528360748637781274">"Pomoč in povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index c907e22..504d821 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ky telefon"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ky tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ky kompjuter (i brendshëm)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altoparlanti i stacionit"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Pajisja e jashtme"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Lidhur përmes ARC-së"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Lidhur përmes eARC-së"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Parazgjedhja e televizorit"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Dalja HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Altoparlantët e brendshëm"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem me lidhjen. Fike dhe ndize përsëri pajisjen"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Pajisja audio me tel"</string>
     <string name="help_label" msgid="3528360748637781274">"Ndihma dhe komentet"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 65000e4..b2dc5fe 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Овај телефон"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Овај таблет"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Овај рачунар (интерно)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Звучник базне станице"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Спољни уређај"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Повезано преко ARC-а"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Повезано преко eARC-а"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Подразумевана вредност за ТВ"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI излаз"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Унутрашњи звучници"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем при повезивању. Искључите уређај, па га поново укључите"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичани аудио уређај"</string>
     <string name="help_label" msgid="3528360748637781274">"Помоћ и повратне информације"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 12c1729..aaa90e0 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Den här telefonen"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Den här surfplattan"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Den här datorn (intern)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dockningsstationens högtalare"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Extern enhet"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Ansluten via ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Ansluten via eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Standardutgång för tv:n"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI-utgång"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Interna högtalare"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Det gick inte att ansluta. Stäng av enheten och slå på den igen"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Ljudenhet med kabelanslutning"</string>
     <string name="help_label" msgid="3528360748637781274">"Hjälp och feedback"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 1bf5677..99d2949 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Simu hii"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Kishikwambi hiki"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Kompyuta hii (spika ya ndani)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Spika ya kituo"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Kifaa cha Nje"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Imeunganishwa kupitia ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Imeunganishwa kupitia eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Mipangilio Chaguomsingi ya TV"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Kutoa sauti kupitia HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Spika za ndani"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Kuna tatizo la kuunganisha kwenye Intaneti. Zima kisha uwashe kifaa"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kifaa cha sauti kinachotumia waya"</string>
     <string name="help_label" msgid="3528360748637781274">"Usaidizi na maoni"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 8ee8fa2..fa2819c 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"இந்த மொபைல்"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"இந்த டேப்லெட்"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"இந்தக் கம்ப்யூட்டர் (அகம்)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"டாக் ஸ்பீக்கர்"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"வெளிப்புறச் சாதனம்"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC மூலம் இணைக்கப்பட்டுள்ளவை"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC மூலம் இணைக்கப்பட்டுள்ளவை"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"டிவி இயல்புநிலை"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI அவுட்புட்"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"உட்புற ஸ்பீக்கர்கள்"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"இணைப்பதில் சிக்கல். சாதனத்தை ஆஃப் செய்து மீண்டும் ஆன் செய்யவும்"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"வயருடன்கூடிய ஆடியோ சாதனம்"</string>
     <string name="help_label" msgid="3528360748637781274">"உதவியும் கருத்தும்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 46350d5..84fb65b 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ఈ ఫోన్"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ఈ టాబ్లెట్"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ఈ కంప్యూటర్ (ఇంటర్నల్)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"డాక్ స్పీకర్"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ఎక్స్‌టర్నల్ పరికరం"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC ద్వారా కనెక్ట్ చేయబడింది"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC ద్వారా కనెక్ట్ చేయబడింది"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"టీవీ ఆటోమేటిక్ సెట్టింగ్"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI అవుట్‌పుట్"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"అంతర్గత స్పీకర్‌లు"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"కనెక్ట్ చేయడంలో సమస్య ఉంది. పరికరాన్ని ఆఫ్ చేసి, ఆపై తిరిగి ఆన్ చేయండి"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"వైర్ గల ఆడియో పరికరం"</string>
     <string name="help_label" msgid="3528360748637781274">"సహాయం &amp; ఫీడ్‌బ్యాక్"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 460782a..22a2a5b 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -304,7 +304,7 @@
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"เลือกเวอร์ชันของบลูทูธ AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"เวอร์ชันของบลูทูธ MAP"</string>
     <string name="bluetooth_select_map_version_dialog_title" msgid="7085934373987428460">"เลือกเวอร์ชันของบลูทูธ MAP"</string>
-    <string name="bluetooth_select_a2dp_codec_type" msgid="952001408455456494">"ตัวแปลงสัญญาณเสียงบลูทูธ"</string>
+    <string name="bluetooth_select_a2dp_codec_type" msgid="952001408455456494">"ตัวแปลงรหัสเสียงบลูทูธ"</string>
     <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"ทริกเกอร์การเลือกตัวแปลงรหัส\nเสียงบลูทูธ"</string>
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"อัตราตัวอย่างเสียงบลูทูธ"</string>
     <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"ทริกเกอร์การเลือกตัวแปลงรหัส\nเสียงบลูทูธ: อัตราตัวอย่าง"</string>
@@ -313,7 +313,7 @@
     <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"ทริกเกอร์การเลือกตัวแปลงรหัส\nเสียงบลูทูธ: บิตต่อตัวอย่าง"</string>
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"โหมดช่องสัญญาณเสียงบลูทูธ"</string>
     <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="2076949781460359589">"ทริกเกอร์การเลือกตัวแปลงรหัส\nเสียงบลูทูธ: โหมดช่องสัญญาณ"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3233402355917446304">"ตัวแปลงสัญญาณเสียงบลูทูธที่ใช้ LDAC: คุณภาพการเล่น"</string>
+    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3233402355917446304">"ตัวแปลงรหัสเสียงบลูทูธที่ใช้ LDAC: คุณภาพการเล่น"</string>
     <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="7274396574659784285">"ทริกเกอร์การเลือกตัวแปลงรหัส LDAC\nเสียงบลูทูธ: คุณภาพการเล่น"</string>
     <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"สตรีมมิง: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
     <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"DNS ส่วนตัว"</string>
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"โทรศัพท์เครื่องนี้"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"แท็บเล็ตเครื่องนี้"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"คอมพิวเตอร์เครื่องนี้ (ภายใน)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"แท่นชาร์จที่มีลำโพง"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"อุปกรณ์ภายนอก"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"เชื่อมต่อผ่าน ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"เชื่อมต่อผ่าน eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"ค่าเริ่มต้นของทีวี"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"เอาต์พุต HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"ลำโพงของเครื่อง"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"เกิดปัญหาในการเชื่อมต่อ ปิดอุปกรณ์แล้วเปิดใหม่อีกครั้ง"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"อุปกรณ์เสียงแบบมีสาย"</string>
     <string name="help_label" msgid="3528360748637781274">"ความช่วยเหลือและความคิดเห็น"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 986b7771..2d094e3 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ang teleponong ito"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ang tablet na ito"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Sa computer na ito (internal)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Speaker ng dock"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"External na Device"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Nakakonekta sa pamamagitan ng ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Nakakonekta sa pamamagitan ng eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Default ng TV"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI output"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Mga internal speaker"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Nagkaproblema sa pagkonekta. I-off at pagkatapos ay i-on ang device"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired na audio device"</string>
     <string name="help_label" msgid="3528360748637781274">"Tulong at feedback"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index df47dac..5f15fc2 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Bu telefon"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Bu tablet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Bu bilgisayar (dahili)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Yuva hoparlörü"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Harici Cihaz"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC ile bağlandı"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC ile bağlandı"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV varsayılanı"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI çıkışı"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Dahili hoparlörler"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Bağlanırken sorun oluştu. Cihazı kapatıp tekrar açın"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kablolu ses cihazı"</string>
     <string name="help_label" msgid="3528360748637781274">"Yardım ve geri bildirim"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 3ba99a2..0385ca0 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Цей телефон"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Цей планшет"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Цей комп’ютер (внутрішній)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Динамік док-станції"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Зовнішній пристрій"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Підключено через ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Підключено через eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Стандартний вихід телевізора"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Вихід HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Внутрішні динаміки"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Не вдається підключитися. Перезавантажте пристрій."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Дротовий аудіопристрій"</string>
     <string name="help_label" msgid="3528360748637781274">"Довідка й відгуки"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index e5e29fa..85472d6 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"یہ فون"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"یہ ٹیبلیٹ"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"یہ کمپیوٹر (داخلی)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ڈاک اسپیکر"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"بیرونی آلہ"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"‏ARC کے ذریعے منسلک ہے"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"‏eARC کے ذریعے منسلک ہے"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"‏TV ڈیفالٹ"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"‏HDMI آؤٹ پٹ"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"اندرونی اسپیکرز"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"منسلک کرنے میں مسئلہ پیش آ گیا۔ آلہ کو آف اور بیک آن کریں"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"وائرڈ آڈیو آلہ"</string>
     <string name="help_label" msgid="3528360748637781274">"مدد اور تاثرات"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 2417d55..d556082 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Shu telefon"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Shu planshet"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Bu kompyuter (ichki)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dok-stansiyali karnay"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Tashqi qurilma"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC orqali ulangan"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC orqali ulangan"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Televizorda birlamchi"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI chiqishi"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Ichki karnaylar"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ulanishda muammo yuz berdi. Qurilmani oʻchiring va yoqing"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio qurilma"</string>
     <string name="help_label" msgid="3528360748637781274">"Yordam/fikr-mulohaza"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 0239a3f..d70019c 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Điện thoại này"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Máy tính bảng này"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Máy tính này (nội bộ)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Loa có gắn đế"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Thiết bị bên ngoài"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Đã kết nối qua ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Đã kết nối qua eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"Chế độ mặc định của TV"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Đầu ra HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Các loa trong"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sự cố kết nối. Hãy tắt thiết bị rồi bật lại"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Thiết bị âm thanh có dây"</string>
     <string name="help_label" msgid="3528360748637781274">"Trợ giúp và phản hồi"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 22bfda4..1c67933 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -359,7 +359,7 @@
     <string name="enable_terminal_summary" msgid="2481074834856064500">"启用终端应用,以便在本地访问 Shell"</string>
     <string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux 开发环境"</string>
     <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(实验性)在 Android 上运行 Linux 终端"</string>
-    <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"如果您停用它,Linux 终端数据会被清除"</string>
+    <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"停用后,Linux 终端数据会被清除"</string>
     <string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP 检查"</string>
     <string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"设置 HDCP 检查行为"</string>
     <string name="debug_debugging_category" msgid="535341063709248842">"调试"</string>
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"这部手机"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"这部平板电脑"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"此计算机(内部)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"基座音箱"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部设备"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"已通过 ARC 连接"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"已通过 eARC 连接"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"电视默认设置"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI 输出"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"内置扬声器"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"连接时遇到问题。请关闭并重新开启设备"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有线音频设备"</string>
     <string name="help_label" msgid="3528360748637781274">"帮助和反馈"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 594273a..2a8c1ee 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"此手機"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"此平板電腦"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"此電腦 (內置)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"插座喇叭"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部裝置"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"已透過 ARC 連接"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"已透過 eARC 連接"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"電視預設的音訊輸出"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI 輸出"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"內置喇叭"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"無法連接,請關閉裝置然後重新開機"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線音響裝置"</string>
     <string name="help_label" msgid="3528360748637781274">"說明與意見反映"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 483dbf3..beb30df 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"這支手機"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"這台平板電腦"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"這部電腦 (內部)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"座架喇叭"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部裝置"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"透過 ARC 連線"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"透過 eARC 連線"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"電視預設的音訊輸出裝置"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI 輸出裝置"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"內建揚聲器"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"無法連線,請關閉裝置後再重新開啟"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線音訊裝置"</string>
     <string name="help_label" msgid="3528360748637781274">"說明與意見回饋"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 2bb3f22..1031bb7 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -586,7 +586,7 @@
     <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Le foni"</string>
     <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Le thebhulethi"</string>
     <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Le khompyutha (ngaphakathi)"</string>
-    <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
+    <!-- no translation found for media_transfer_this_device_name_tv (8508713779441163887) -->
     <skip />
     <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Isipikha sentuba"</string>
     <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Idivayisi Yangaphandle"</string>
@@ -607,9 +607,10 @@
     <string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"I-HDMI eARC"</string>
     <string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Ixhunywe nge-ARC"</string>
     <string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Ixhunywe nge-eARC"</string>
-    <string name="tv_media_transfer_default" msgid="5403053145185843843">"I-TV ezenzakalelayo"</string>
-    <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"umphumela we-HDMI"</string>
-    <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Izipikha zangaphakathi"</string>
+    <!-- no translation found for tv_media_transfer_internal_speakers (4662765121700213785) -->
+    <skip />
+    <!-- no translation found for tv_media_transfer_hdmi_title (6715658310934507444) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Inkinga yokuxhumeka. Vala idivayisi futhi uphinde uyivule"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Idivayisi yomsindo enentambo"</string>
     <string name="help_label" msgid="3528360748637781274">"Usizo nempendulo"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index f03014c..eaf155d 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1419,7 +1419,7 @@
     <!-- Name of the internal speaker and mic. [CHAR LIMIT=30] -->
     <string name="media_transfer_this_device_name_desktop">This computer (internal)</string>
     <!-- Name of the default media output of the TV. [CHAR LIMIT=30] -->
-    <string name="media_transfer_this_device_name_tv">@string/tv_media_transfer_default</string>
+    <string name="media_transfer_this_device_name_tv">This TV</string>
     <!-- Name of the dock device. [CHAR LIMIT=30] -->
     <string name="media_transfer_dock_speaker_device_name">Dock speaker</string>
     <!-- Default name of the external device. [CHAR LIMIT=30] -->
@@ -1462,12 +1462,11 @@
     <!-- Media output switcher. Subtitle for devices connected through HDMI EARC if a device name is available. [CHAR LIMIT=NONE] -->
     <string name="tv_media_transfer_earc_subtitle">Connected via eARC</string>
 
-    <!-- TV media output switcher. Title for the default audio output of the device [CHAR LIMIT=NONE] -->
-    <string name="tv_media_transfer_default">TV default</string>
-    <!-- TV media output switcher. Subtitle for default audio output which is HDMI, e.g. TV dongle [CHAR LIMIT=NONE] -->
-    <string name="tv_media_transfer_hdmi">HDMI output</string>
-    <!-- TV media output switcher. Subtitle for default audio output which is internal speaker, i.e. panel VTs [CHAR LIMIT=NONE] -->
-    <string name="tv_media_transfer_internal_speakers">Internal speakers</string>
+    <!-- TV media output switcher. Subtitle for default audio output which is internal speaker [CHAR LIMIT=NONE] -->
+    <string name="tv_media_transfer_internal_speakers">Built-in speaker</string>
+
+    <!-- TV media output switcher. Title for default audio output which is HDMI, e.g. TV dongle [CHAR LIMIT=NONE] -->
+    <string name="tv_media_transfer_hdmi_title">TV Audio</string>
 
     <!-- Warning message to tell user is have problem during profile connect, it need to turn off device and back on. [CHAR_LIMIT=NONE] -->
     <string name="profile_connect_timeout_subtext">Problem connecting. Turn device off &amp; back on</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
index b3e48b2..fa28cf6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
@@ -94,6 +94,14 @@
     boolean setSubDeviceIfNeeded(CachedBluetoothDevice newDevice) {
         final long hiSyncId = newDevice.getHiSyncId();
         if (isValidHiSyncId(hiSyncId)) {
+            // The remote device supports CSIP, the other ear should be processed as a member
+            // device. Ignore hiSyncId grouping from ASHA here.
+            if (newDevice.getProfiles().stream().anyMatch(
+                    profile -> profile instanceof CsipSetCoordinatorProfile)) {
+                Log.w(TAG, "Skip ASHA grouping since this device supports CSIP");
+                return false;
+            }
+
             final CachedBluetoothDevice hearingAidDevice = getCachedDevice(hiSyncId);
             // Just add one of the hearing aids from a pair in the list that is shown in the UI.
             // Once there is another device with the same hiSyncId, to add new device as sub
@@ -161,6 +169,7 @@
             // device. Ignore hiSyncId grouping from ASHA here.
             if (cachedDevice.getProfiles().stream().anyMatch(
                     profile -> profile instanceof CsipSetCoordinatorProfile)) {
+                Log.w(TAG, "Skip ASHA grouping since this device supports CSIP");
                 continue;
             }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastCallbackExt.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastCallbackExt.kt
index 07abb6b..888f54f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastCallbackExt.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastCallbackExt.kt
@@ -69,8 +69,8 @@
             }
             .buffer(capacity = Channel.CONFLATED)
 
-/** [Flow] for [BluetoothLeBroadcast.Callback] onPlaybackStarted event */
-val LocalBluetoothLeBroadcast.onPlaybackStarted: Flow<Unit>
+/** [Flow] for [BluetoothLeBroadcast.Callback] onBroadcastMetadataChanged event */
+val LocalBluetoothLeBroadcast.onBroadcastMetadataChanged: Flow<Unit>
     get() =
         callbackFlow {
             val listener =
@@ -87,7 +87,6 @@
                     }
 
                     override fun onPlaybackStarted(reason: Int, broadcastId: Int) {
-                        launch { trySend(Unit) }
                     }
 
                     override fun onPlaybackStopped(reason: Int, broadcastId: Int) {
@@ -100,7 +99,9 @@
                     override fun onBroadcastMetadataChanged(
                         broadcastId: Int,
                         metadata: BluetoothLeBroadcastMetadata
-                    ) {}
+                    ) {
+                        trySend(Unit)
+                    }
                 }
             registerServiceCallBack(
                 ConcurrentUtils.DIRECT_EXECUTOR,
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java b/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java
index 717a8ee..aa2ede31 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java
@@ -33,6 +33,8 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
 import android.media.MediaRoute2Info;
 import android.os.SystemProperties;
 import android.util.SparseIntArray;
@@ -116,14 +118,15 @@
 
     @SuppressLint("SwitchIntDef")
     @DrawableRes
-    private static int getIconResourceIdForTv(@MediaRoute2Info.Type int type) {
+    private int getIconResourceIdForTv(@MediaRoute2Info.Type int type) {
         return switch (type) {
             case MediaRoute2Info.TYPE_USB_DEVICE, MediaRoute2Info.TYPE_USB_HEADSET ->
                     R.drawable.ic_headphone;
             case MediaRoute2Info.TYPE_USB_ACCESSORY -> R.drawable.ic_usb;
             case MediaRoute2Info.TYPE_DOCK -> R.drawable.ic_dock_device;
-            case MediaRoute2Info.TYPE_HDMI, MediaRoute2Info.TYPE_BUILTIN_SPEAKER ->
-                    R.drawable.ic_tv;
+            case MediaRoute2Info.TYPE_BUILTIN_SPEAKER ->
+                    isPanelTv() ? R.drawable.ic_tv : R.drawable.ic_tv_box_internal_speaker;
+            case MediaRoute2Info.TYPE_HDMI -> R.drawable.ic_tv;
             case MediaRoute2Info.TYPE_HDMI_ARC, MediaRoute2Info.TYPE_HDMI_EARC ->
                     R.drawable.ic_hdmi;
             case MediaRoute2Info.TYPE_WIRED_HEADSET, MediaRoute2Info.TYPE_WIRED_HEADPHONES ->
@@ -132,6 +135,23 @@
         };
     }
 
+    private boolean isPanelTv() {
+        if (mContext == null) {
+            // This should only happen during testing.
+            return true;
+        }
+        AudioManager audioManager = mContext.getSystemService(AudioManager.class);
+        AudioDeviceInfo[] devices = audioManager.getDevices(
+                AudioManager.GET_DEVICES_OUTPUTS);
+        // If we have an HDMI output (not ARC/eARC) we can assume it's a dongle / set top box.
+        for (AudioDeviceInfo device : devices) {
+            if (device.getType() == TYPE_HDMI) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     static {
         AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(TYPE_USB_DEVICE, MediaRoute2Info.TYPE_USB_DEVICE);
         AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(TYPE_USB_HEADSET, MediaRoute2Info.TYPE_USB_HEADSET);
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index 2321097..b01b7c9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -390,6 +390,16 @@
     }
 
     /**
+     * Get the {@link MediaRoute2Info.Type} of the device.
+     */
+    public int getRouteType() {
+        if (mRouteInfo == null) {
+            return TYPE_UNKNOWN;
+        }
+        return mRouteInfo.getType();
+    }
+
+    /**
      * Checks if route's volume is fixed, if true, we should disable volume control for the device.
      *
      * @return route for this device is fixed.
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index 4766a86..6ff1a99 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -29,6 +29,7 @@
 import static android.media.MediaRoute2Info.TYPE_LINE_DIGITAL;
 import static android.media.MediaRoute2Info.TYPE_LINE_ANALOG;
 import static android.media.MediaRoute2Info.TYPE_AUX_LINE;
+
 import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER;
 
 import android.Manifest;
@@ -40,6 +41,7 @@
 import android.hardware.hdmi.HdmiPortInfo;
 import android.media.MediaRoute2Info;
 import android.media.RouteListingPreference;
+import android.os.Build;
 import android.os.SystemProperties;
 import android.util.Log;
 
@@ -72,7 +74,7 @@
     /** Returns this device name for media transfer. */
     public static @NonNull String getMediaTransferThisDeviceName(@NonNull Context context) {
         if (isTv(context)) {
-            return context.getString(R.string.media_transfer_this_device_name_tv);
+            return Build.MODEL;
         } else if (isTablet()) {
             return context.getString(R.string.media_transfer_this_device_name_tablet);
         } else if (inputRoutingEnabledAndIsDesktop(context)) {
@@ -110,7 +112,7 @@
                 name = getMediaTransferThisDeviceName(context);
                 break;
             case TYPE_HDMI:
-                name = context.getString(isTv ? R.string.tv_media_transfer_default :
+                name = context.getString(isTv ? R.string.tv_media_transfer_hdmi_title :
                         R.string.media_transfer_external_device_name);
                 break;
             case TYPE_HDMI_ARC:
@@ -223,8 +225,6 @@
         switch (mRouteInfo.getType()) {
             case TYPE_BUILTIN_SPEAKER:
                 return mContext.getString(R.string.tv_media_transfer_internal_speakers);
-            case TYPE_HDMI:
-                return mContext.getString(R.string.tv_media_transfer_hdmi);
             case TYPE_HDMI_ARC:
                 if (getHdmiOutDeviceName(mContext) == null) {
                     // Connection type is already part of the title.
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/AppIconCacheManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/AppIconCacheManagerTest.java
index 1b0e1f1..013ff92 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/AppIconCacheManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/AppIconCacheManagerTest.java
@@ -16,11 +16,14 @@
 
 package com.android.settingslib.applications;
 
+import static android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.doReturn;
 
 import android.graphics.drawable.Drawable;
+import android.util.Log;
 
 import org.junit.After;
 import org.junit.Before;
@@ -30,9 +33,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 
+import java.util.concurrent.atomic.AtomicInteger;
+
 @RunWith(RobolectricTestRunner.class)
 public class AppIconCacheManagerTest {
 
+    private static final String TAG = "AppIconCacheManagerTest";
     private static final String APP_PACKAGE_NAME = "com.test.app";
     private static final String APP_PACKAGE_NAME1 = "com.test.app1";
     private static final String APP_PACKAGE_NAME2 = "com.test.app2";
@@ -176,4 +182,28 @@
         assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME2, APP_UID)).isNull();
         assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME3, APP_UID)).isNull();
     }
+
+    @Test
+    public void trimMemory_multiThread_shouldNotCrash() {
+        int numberOfTasks = 10;
+        AtomicInteger completedTasks = new AtomicInteger(0);
+
+        Runnable task =
+                () -> {
+                    String threadName = Thread.currentThread().getName();
+                    Log.i(TAG, "Starting thread: " + threadName);
+                    AppIconCacheManager.getInstance().trimMemory(TRIM_MEMORY_BACKGROUND);
+                    completedTasks.incrementAndGet();
+                    Log.i(TAG, "Ending thread: " + threadName);
+                };
+
+        for (Integer i = 0; i < numberOfTasks; i++) {
+            Thread thread = new Thread(task);
+            thread.start();
+        }
+
+        while (completedTasks.get() < numberOfTasks) {
+            // Wait until all threads are finished.
+        }
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/DeviceIconUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/DeviceIconUtilTest.java
index 883640d..5ac22a7 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/DeviceIconUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/DeviceIconUtilTest.java
@@ -173,7 +173,7 @@
     public void getIconResIdFromMediaRouteType_tv_builtinSpeaker_isTv() {
         assertThat(new DeviceIconUtil(/* isTv */ true)
                 .getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_BUILTIN_SPEAKER))
-                .isEqualTo(R.drawable.ic_tv);
+                .isAnyOf(R.drawable.ic_tv, R.drawable.ic_tv_box_internal_speaker);
     }
 
     @Test
@@ -331,7 +331,7 @@
     public void getIconResIdFromAudioDeviceType_tv_builtinSpeaker_isTv() {
         assertThat(new DeviceIconUtil(/* isTv */ true)
                 .getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER))
-                .isEqualTo(R.drawable.ic_tv);
+                .isAnyOf(R.drawable.ic_tv, R.drawable.ic_tv_box_internal_speaker);
     }
 
     @Test
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 927a1c59..1f291cd 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -107,6 +107,8 @@
         Settings.Secure.DISPLAY_WHITE_BALANCE_ENABLED,
         Settings.Secure.SYNC_PARENT_SOUNDS,
         Settings.Secure.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
+        Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED,
+        Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE,
         Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
         Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED,
         // ACCESSIBILITY_QS_TARGETS needs to be restored after ENABLED_ACCESSIBILITY_SERVICES
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index 8e7180c..935ea25 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -119,7 +119,8 @@
                 Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR,
                 Settings.System.NOTIFICATION_COOLDOWN_ENABLED,
                 Settings.System.NOTIFICATION_COOLDOWN_ALL,
-                Settings.System.NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED
+                Settings.System.NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED,
+                Settings.System.PREFERRED_REGION
         ));
         if (Flags.backUpSmoothDisplayAndForcePeakRefreshRate()) {
             settings.add(Settings.System.PEAK_REFRESH_RATE);
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 6d73ee2..abd5b9a 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -160,6 +160,9 @@
         VALIDATORS.put(Secure.DISPLAY_WHITE_BALANCE_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SYNC_PARENT_SOUNDS, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE,
+                new InclusiveIntegerRangeValidator(0, 1));
         VALIDATORS.put(Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SYSTEM_NAVIGATION_KEYS_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.QS_TILES, TILE_LIST_VALIDATOR);
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index cfc7743..9938139 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -265,5 +265,6 @@
         VALIDATORS.put(System.NOTIFICATION_COOLDOWN_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.NOTIFICATION_COOLDOWN_ALL, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.PREFERRED_REGION, ANY_STRING_VALIDATOR);
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/OWNERS b/packages/SettingsProvider/src/com/android/providers/settings/OWNERS
index 0b71816..b0086c1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/OWNERS
+++ b/packages/SettingsProvider/src/com/android/providers/settings/OWNERS
@@ -1 +1,2 @@
-per-file WritableNamespacePrefixes.java = cbrubaker@google.com,tedbauer@google.com
+per-file WritableNamespacePrefixes.java = mpgroover@google.com,tedbauer@google.com
+per-file WritableNamespaces.java = mpgroover@google.com,tedbauer@google.com
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 600c36e..5ae11ba 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -2124,6 +2124,15 @@
                 SecureSettingsProto.Display.SCREEN_RESOLUTION_MODE);
         p.end(displayToken);
 
+        final long doubleTapPowerButtonToken = p.start(SecureSettingsProto.DOUBLE_TAP_POWER_BUTTON);
+        dumpSetting(s, p,
+                Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED,
+                SecureSettingsProto.DoubleTapPowerButton.GESTURE_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE,
+                SecureSettingsProto.DoubleTapPowerButton.GESTURE);
+        p.end(doubleTapPowerButtonToken);
+
         final long dozeToken = p.start(SecureSettingsProto.DOZE);
         dumpSetting(s, p,
                 Settings.Secure.DOZE_ENABLED,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 03fea37..6128d45 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -130,10 +130,12 @@
 
 import libcore.util.HexEncoding;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
+import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -380,6 +382,8 @@
     @GuardedBy("mLock")
     private Handler mHandler;
 
+    private static final Set<String> sDeviceConfigAllowlistedNamespaces = new ArraySet<>();
+
     // We have to call in the user manager with no lock held,
     private volatile UserManager mUserManager;
 
@@ -2442,6 +2446,10 @@
         if (!isRestrictedShell && hasWritePermission) {
             assertCallingUserDenyList(flags);
         } else if (hasAllowlistPermission) {
+            Set<String> allowlistedDeviceConfigNamespaces = null;
+            if (isRestrictedShell) {
+                allowlistedDeviceConfigNamespaces = getAllowlistedDeviceConfigNamespaces();
+            }
             for (String flag : flags) {
                 boolean namespaceAllowed = false;
                 if (isRestrictedShell) {
@@ -2452,7 +2460,7 @@
                     } else {
                         flagNamespace = flag;
                     }
-                    if (WritableNamespaces.ALLOWLIST.contains(flagNamespace)) {
+                    if (allowlistedDeviceConfigNamespaces.contains(flagNamespace)) {
                         namespaceAllowed = true;
                     }
                 } else {
@@ -2513,6 +2521,60 @@
         }
     }
 
+    /**
+     * Returns a Set of DeviceConfig allowlisted namespaces in which all flags can be modified
+     * by a caller with the {@code WRITE_ALLOWLISTED_DEVICE_CONFIG} permission.
+     * <p>
+     * This method also supports mainline modules that introduce their own allowlisted
+     * namespaces within the {@code etc/writable_namespaces} file under their directory.
+     */
+    private Set<String> getAllowlistedDeviceConfigNamespaces() {
+        synchronized (sDeviceConfigAllowlistedNamespaces) {
+            if (!sDeviceConfigAllowlistedNamespaces.isEmpty()) {
+                return sDeviceConfigAllowlistedNamespaces;
+            }
+            if (android.provider.flags.Flags.deviceConfigWritableNamespacesApi()) {
+                sDeviceConfigAllowlistedNamespaces.addAll(DeviceConfig.getAdbWritableNamespaces());
+            } else {
+                sDeviceConfigAllowlistedNamespaces.addAll(WritableNamespaces.ALLOWLIST);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                List<String> apexDirectories;
+                try {
+                    apexDirectories = mPackageManager.getAllApexDirectories();
+                } catch (RemoteException e) {
+                    Slog.e(LOG_TAG, "Caught a RemoteException obtaining APEX directories: ", e);
+                    return sDeviceConfigAllowlistedNamespaces;
+                }
+                for (int i = 0; i < apexDirectories.size(); i++) {
+                    String apexDirectory = apexDirectories.get(i);
+                    File namespaceFile = Environment.buildPath(new File(apexDirectory), "etc",
+                            "writable_namespaces");
+                    if (namespaceFile.exists() && namespaceFile.isFile()) {
+                        try (BufferedReader reader = new BufferedReader(
+                                new FileReader(namespaceFile))) {
+                            String namespace;
+                            while ((namespace = reader.readLine()) != null) {
+                                namespace = namespace.trim();
+                                // Support comments by ignoring any lines that start with '#'.
+                                if (!namespace.isEmpty() && !namespace.startsWith("#")) {
+                                    sDeviceConfigAllowlistedNamespaces.add(namespace);
+                                }
+                            }
+                        } catch (IOException e) {
+                            Slog.e(LOG_TAG, "Caught an exception parsing file: " + namespaceFile,
+                                    e);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+            return sDeviceConfigAllowlistedNamespaces;
+        }
+    }
+
     private static void warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
             int targetSdkVersion, String name) {
         // If the app targets Lollipop MR1 or older SDK we warn, otherwise crash.
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespaces.java b/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespaces.java
index d835c5f..5ce97eb 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespaces.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespaces.java
@@ -33,6 +33,16 @@
 final class WritableNamespaces {
     public static final Set<String> ALLOWLIST =
             new ArraySet<String>(Arrays.asList(
-                    "exo"
+                    "adservices",
+                    "captive_portal_login",
+                    "connectivity",
+                    "exo",
+                    "nearby",
+                    "netd_native",
+                    "network_security",
+                    "on_device_personalization",
+                    "tethering",
+                    "tethering_u_or_later_native",
+                    "thread_network"
             ));
 }
diff --git a/packages/Shell/Android.bp b/packages/Shell/Android.bp
index 3350efc..5f81085 100644
--- a/packages/Shell/Android.bp
+++ b/packages/Shell/Android.bp
@@ -27,6 +27,7 @@
     ],
     flags_packages: [
         "android.security.flags-aconfig",
+        "android.permission.flags-aconfig",
     ],
     platform_apis: true,
     certificate: "platform",
@@ -51,5 +52,6 @@
     manifest: "AndroidManifest.xml",
     flags_packages: [
         "android.security.flags-aconfig",
+        "android.permission.flags-aconfig",
     ],
 }
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index b761d6a..0ec5571 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -151,7 +151,8 @@
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     <uses-permission android:name="android.permission.LOCATION_BYPASS" />
     <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
-    <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
+    <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG"
+        android:featureFlag="!android.security.protect_device_config_flags"/>
     <uses-permission android:name="android.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.READ_WRITE_SYNC_DISABLED_MODE_CONFIG" />
     <uses-permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS" />
@@ -956,7 +957,7 @@
     <!-- Permission required for CTS test - CtsNfcTestCases -->
     <uses-permission android:name="android.permission.NFC_SET_CONTROLLER_ALWAYS_ON" />
     <!-- Permission required for CTS test - AdvancedProtectionManagerTest -->
-    <uses-permission android:name="android.permission.SET_ADVANCED_PROTECTION_MODE"
+    <uses-permission android:name="android.permission.MANAGE_ADVANCED_PROTECTION_MODE"
         android:featureFlag="android.security.aapm_api"/>
     <uses-permission android:name="android.permission.QUERY_ADVANCED_PROTECTION_MODE"
         android:featureFlag="android.security.aapm_api"/>
@@ -974,13 +975,21 @@
     <!-- Permission required for CTS test - CtsTelephonyTestCases -->
     <uses-permission android:name="android.permission.READ_BASIC_PHONE_STATE" />
 
-    <!-- Permission required for ExecutableMethodFileOffsetsTest -->
+    <!-- Permission required for CTS test - CtsDynamicInstrumentationManagerTest -->
     <uses-permission android:name="android.permission.DYNAMIC_INSTRUMENTATION" />
 
     <!-- Permissions required for CTS test - SettingsPreferenceServiceClientTest -->
     <uses-permission android:name="android.permission.READ_SYSTEM_PREFERENCES" />
     <uses-permission android:name="android.permission.WRITE_SYSTEM_PREFERENCES" />
 
+    <!-- Permissions required for CTS test - ActivityManagerForegroundServiceTypeTest -->
+    <uses-permission android:name="android.permission.health.READ_HEART_RATE"
+        android:featureFlag="android.permission.flags.replace_body_sensor_permission_enabled"/>
+    <uses-permission android:name="android.permission.health.READ_OXYGEN_SATURATION"
+        android:featureFlag="android.permission.flags.replace_body_sensor_permission_enabled"/>
+    <uses-permission android:name="android.permission.health.READ_SKIN_TEMPERATURE"
+        android:featureFlag="android.permission.flags.replace_body_sensor_permission_enabled"/>
+
     <application
         android:label="@string/app_label"
         android:theme="@android:style/Theme.DeviceDefault.DayNight"
diff --git a/packages/StatementService/Android.bp b/packages/StatementService/Android.bp
index 90e1808..39b0302 100644
--- a/packages/StatementService/Android.bp
+++ b/packages/StatementService/Android.bp
@@ -38,8 +38,10 @@
         "StatementServiceParser",
         "androidx.appcompat_appcompat",
         "androidx.collection_collection-ktx",
+        "androidx.room_room-runtime",
         "androidx.work_work-runtime",
         "androidx.work_work-runtime-ktx",
         "kotlinx-coroutines-android",
     ],
+    plugins: ["androidx.room_room-compiler-plugin"],
 }
diff --git a/packages/StatementService/src/com/android/statementservice/StatementServiceApplication.kt b/packages/StatementService/src/com/android/statementservice/StatementServiceApplication.kt
index 021a514..6af8004 100644
--- a/packages/StatementService/src/com/android/statementservice/StatementServiceApplication.kt
+++ b/packages/StatementService/src/com/android/statementservice/StatementServiceApplication.kt
@@ -30,6 +30,7 @@
             // WorkManager can only schedule when the user data directories are unencrypted (after
             // the user has entered their lock password.
             DomainVerificationUtils.schedulePeriodicCheckUnlocked(WorkManager.getInstance(this))
+            DomainVerificationUtils.schedulePeriodicUpdateUnlocked(WorkManager.getInstance(this))
         }
     }
 }
diff --git a/packages/StatementService/src/com/android/statementservice/database/Converters.kt b/packages/StatementService/src/com/android/statementservice/database/Converters.kt
new file mode 100644
index 0000000..21ecc8b
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/database/Converters.kt
@@ -0,0 +1,130 @@
+/*
+ * 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.statementservice.database
+
+import android.content.UriRelativeFilter
+import android.content.UriRelativeFilterGroup
+import android.util.JsonReader
+import androidx.room.TypeConverter
+import org.json.JSONArray
+import org.json.JSONObject
+import java.io.StringReader
+import java.util.ArrayList
+
+class Converters {
+    companion object {
+        private const val ACTION_NAME = "action"
+        private const val FILTERS_NAME = "filters"
+        private const val URI_PART_NAME = "uriPart"
+        private const val PATTERN_TYPE_NAME = "patternType"
+        private const val FILTER_NAME = "filter"
+    }
+
+    @TypeConverter
+    fun groupsToJson(groups: List<UriRelativeFilterGroup>): String {
+        val json = JSONArray()
+        for (group in groups) {
+            json.put(groupToJson(group))
+        }
+        return json.toString()
+    }
+
+    @TypeConverter
+    fun stringToGroups(json: String): List<UriRelativeFilterGroup> {
+        val groups = ArrayList<UriRelativeFilterGroup>()
+        StringReader(json).use { stringReader ->
+            JsonReader(stringReader).use { reader ->
+                reader.beginArray()
+                while (reader.hasNext()) {
+                    groups.add(parseGroup(reader))
+                }
+                reader.endArray()
+            }
+        }
+        return groups
+    }
+
+    private fun groupToJson(group: UriRelativeFilterGroup): JSONObject {
+        val jsonObject = JSONObject()
+        jsonObject.put(ACTION_NAME, group.action)
+        val filters = JSONArray()
+        for (filter in group.uriRelativeFilters) {
+            filters.put(filterToJson(filter))
+        }
+        jsonObject.put(FILTERS_NAME, filters)
+        return jsonObject
+    }
+
+    private fun filterToJson(filter: UriRelativeFilter): JSONObject {
+        val jsonObject = JSONObject()
+        jsonObject.put(URI_PART_NAME, filter.uriPart)
+        jsonObject.put(PATTERN_TYPE_NAME, filter.patternType)
+        jsonObject.put(FILTER_NAME, filter.filter)
+        return jsonObject
+    }
+
+    private fun parseGroup(reader: JsonReader): UriRelativeFilterGroup {
+        val jsonObject = JSONObject()
+        reader.beginObject()
+        while (reader.hasNext()) {
+            val name = reader.nextName()
+            when (name) {
+                ACTION_NAME -> jsonObject.put(ACTION_NAME, reader.nextInt())
+                FILTERS_NAME -> jsonObject.put(FILTERS_NAME, parseFilters(reader))
+                else -> reader.skipValue()
+            }
+        }
+        reader.endObject()
+
+        val group = UriRelativeFilterGroup(jsonObject.getInt(ACTION_NAME))
+        val filters = jsonObject.getJSONArray(FILTERS_NAME)
+        for (i in 0 until filters.length()) {
+            val filter = filters.getJSONObject(i)
+            group.addUriRelativeFilter(UriRelativeFilter(
+                filter.getInt(URI_PART_NAME),
+                filter.getInt(PATTERN_TYPE_NAME),
+                filter.getString(FILTER_NAME)
+            ))
+        }
+        return group
+    }
+
+    private fun parseFilters(reader: JsonReader): JSONArray {
+        val filters = JSONArray()
+        reader.beginArray()
+        while (reader.hasNext()) {
+            filters.put(parseFilter(reader))
+        }
+        reader.endArray()
+        return filters
+    }
+
+    private fun parseFilter(reader: JsonReader): JSONObject {
+        reader.beginObject()
+        val jsonObject = JSONObject()
+        while (reader.hasNext()) {
+            val name = reader.nextName()
+            when (name) {
+                URI_PART_NAME, PATTERN_TYPE_NAME -> jsonObject.put(name, reader.nextInt())
+                FILTER_NAME -> jsonObject.put(name, reader.nextString())
+                else -> reader.skipValue()
+            }
+        }
+        reader.endObject()
+        return jsonObject
+    }
+}
\ No newline at end of file
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/packages/StatementService/src/com/android/statementservice/database/DomainGroups.kt
similarity index 67%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to packages/StatementService/src/com/android/statementservice/database/DomainGroups.kt
index 7d3d8b9..c616669 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/packages/StatementService/src/com/android/statementservice/database/DomainGroups.kt
@@ -13,10 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
-}
+package com.android.statementservice.database
+
+import android.content.UriRelativeFilterGroup
+import androidx.room.Entity
+
+@Entity(primaryKeys = ["packageName", "domain"])
+data class DomainGroups(
+    val packageName: String,
+    val domain: String,
+    val groups: List<UriRelativeFilterGroup>
+)
\ No newline at end of file
diff --git a/packages/StatementService/src/com/android/statementservice/database/DomainGroupsDao.kt b/packages/StatementService/src/com/android/statementservice/database/DomainGroupsDao.kt
new file mode 100644
index 0000000..3b4dcea
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/database/DomainGroupsDao.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.statementservice.database
+
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.Query
+
+@Dao
+interface DomainGroupsDao {
+    @Query("SELECT * FROM DomainGroups WHERE packageName = :packageName")
+    fun getDomainGroups(packageName: String): List<DomainGroups>
+
+    @Insert
+    fun insertDomainGroups(vararg domainGroups: DomainGroups)
+
+    @Query("DELETE FROM DomainGroups WHERE packageName = :packageName AND domain = :domain")
+    fun clear(packageName: String, domain: String)
+
+    @Query("DELETE FROM DomainGroups WHERE packageName = :packageName")
+    fun clear(packageName: String)
+}
\ No newline at end of file
diff --git a/packages/StatementService/src/com/android/statementservice/database/DomainGroupsDatabase.kt b/packages/StatementService/src/com/android/statementservice/database/DomainGroupsDatabase.kt
new file mode 100644
index 0000000..39833f6
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/database/DomainGroupsDatabase.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.statementservice.database
+
+import android.content.Context
+import androidx.room.Database
+import androidx.room.Room
+import androidx.room.RoomDatabase
+import androidx.room.TypeConverters
+
+@Database(entities = [DomainGroups::class], version = 1)
+@TypeConverters(Converters::class)
+abstract class DomainGroupsDatabase : RoomDatabase() {
+    companion object {
+        private const val DATABASE_NAME = "domain-groups"
+        @Volatile
+        private var instance: DomainGroupsDatabase? = null
+
+        fun getInstance(context: Context) = instance ?: synchronized(this) {
+            instance ?: Room.databaseBuilder(
+                context,
+                DomainGroupsDatabase::class.java, DATABASE_NAME
+            ).build().also { instance = it }
+        }
+    }
+    abstract fun domainGroupsDao(): DomainGroupsDao
+}
\ No newline at end of file
diff --git a/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV1.kt b/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV1.kt
index acb54f6..0d7a1fd 100644
--- a/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV1.kt
+++ b/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV1.kt
@@ -22,6 +22,7 @@
 import androidx.work.ExistingWorkPolicy
 import androidx.work.WorkManager
 import com.android.statementservice.domain.worker.CollectV1Worker
+import com.android.statementservice.domain.worker.GroupUpdateV1Worker
 import com.android.statementservice.domain.worker.SingleV1RequestWorker
 
 /**
@@ -67,7 +68,7 @@
             }
         }
 
-        //clear sp before enqueue unique work since policy is REPLACE
+        // clear sp before enqueue unique work since policy is REPLACE
         val deContext = context.createDeviceProtectedStorageContext()
         val editor = deContext?.getSharedPreferences(packageName, Context.MODE_PRIVATE)?.edit()
         editor?.clear()?.apply()
@@ -78,6 +79,7 @@
                 workRequests
             )
             .then(CollectV1Worker.buildRequest(verificationId, packageName))
+            .then(GroupUpdateV1Worker.buildRequest(packageName))
             .enqueue()
     }
 }
diff --git a/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationUtils.kt b/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationUtils.kt
index 6944248..157a800 100644
--- a/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationUtils.kt
+++ b/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationUtils.kt
@@ -22,6 +22,7 @@
 import androidx.work.PeriodicWorkRequestBuilder
 import androidx.work.WorkManager
 import com.android.statementservice.domain.worker.RetryRequestWorker
+import com.android.statementservice.domain.worker.UpdateVerifiedDomainsWorker
 import java.time.Duration
 
 object DomainVerificationUtils {
@@ -30,6 +31,10 @@
     private const val PERIODIC_SHORT_HOURS = 24L
     private const val PERIODIC_LONG_ID = "retry_long"
     private const val PERIODIC_LONG_HOURS = 72L
+    private const val PERIODIC_UPDATE_ID = "update"
+    private const val PERIODIC_UPDATE_HOURS = 720L
+
+    private const val UPDATE_WORKER_ENABLED = false
 
     /**
      * In a majority of cases, the initial requests will be enough to verify domains, since they
@@ -74,4 +79,38 @@
                 }
         }
     }
+
+    /**
+     * Schedule a periodic worker to check for any updates to assetlink.json files for domains that
+     * have already been verified.
+     *
+     * Due to the potential for this worker to generate enough traffic across all android devices
+     * to overwhelm websites, this method is hardcoded to be disabled by default. It is highly
+     * recommended to not enable this worker and instead implement a custom worker that pulls
+     * updates from a caching service instead of directly from websites.
+     */
+    fun schedulePeriodicUpdateUnlocked(workManager: WorkManager) {
+        if (UPDATE_WORKER_ENABLED) {
+            workManager.apply {
+                PeriodicWorkRequestBuilder<UpdateVerifiedDomainsWorker>(
+                    Duration.ofDays(
+                        PERIODIC_UPDATE_HOURS
+                    )
+                )
+                    .setConstraints(
+                        Constraints.Builder()
+                            .setRequiredNetworkType(NetworkType.CONNECTED)
+                            .setRequiresDeviceIdle(true)
+                            .build()
+                    )
+                    .build()
+                    .let {
+                        enqueueUniquePeriodicWork(
+                            PERIODIC_UPDATE_ID,
+                            ExistingPeriodicWorkPolicy.KEEP, it
+                        )
+                    }
+            }
+        }
+    }
 }
diff --git a/packages/StatementService/src/com/android/statementservice/domain/DomainVerifier.kt b/packages/StatementService/src/com/android/statementservice/domain/DomainVerifier.kt
index 29f844f..c7f6c18 100644
--- a/packages/StatementService/src/com/android/statementservice/domain/DomainVerifier.kt
+++ b/packages/StatementService/src/com/android/statementservice/domain/DomainVerifier.kt
@@ -24,6 +24,7 @@
 import com.android.statementservice.network.retriever.StatementRetriever
 import com.android.statementservice.retriever.AbstractAsset
 import com.android.statementservice.retriever.AbstractAssetMatcher
+import com.android.statementservice.retriever.Statement
 import com.android.statementservice.utils.Result
 import com.android.statementservice.utils.StatementUtils
 import com.android.statementservice.utils.component1
@@ -63,7 +64,8 @@
 
     private val targetAssetCache = AssetLruCache()
 
-    fun collectHosts(packageNames: Iterable<String>): Iterable<Triple<UUID, String, String>> {
+    fun collectHosts(packageNames: Iterable<String>, statusFilter: (Int) -> Boolean):
+            Iterable<Triple<UUID, String, Iterable<String>>> {
         return packageNames.mapNotNull { packageName ->
             val (domainSetId, _, hostToStateMap) = try {
                 manager.getDomainVerificationInfo(packageName)
@@ -73,24 +75,23 @@
             } ?: return@mapNotNull null
 
             val hostsToRetry = hostToStateMap
-                .filterValues(VerifyStatus::shouldRetry)
+                .filterValues(statusFilter)
                 .takeIf { it.isNotEmpty() }
                 ?.map { it.key }
                 ?: return@mapNotNull null
 
-            hostsToRetry.map { Triple(domainSetId, packageName, it) }
+            Triple(domainSetId, packageName, hostsToRetry)
         }
-            .flatten()
     }
 
     suspend fun verifyHost(
         host: String,
         packageName: String,
         network: Network? = null
-    ): Pair<WorkResult, VerifyStatus> {
+    ): Triple<WorkResult, VerifyStatus, Statement?> {
         val assetMatcher = synchronized(targetAssetCache) { targetAssetCache[packageName] }
             .takeIf { it!!.isPresent }
-            ?: return WorkResult.failure() to VerifyStatus.FAILURE_PACKAGE_MANAGER
+            ?: return Triple(WorkResult.failure(), VerifyStatus.FAILURE_PACKAGE_MANAGER, null)
         return verifyHost(host, assetMatcher.get(), network)
     }
 
@@ -98,34 +99,34 @@
         host: String,
         assetMatcher: AbstractAssetMatcher,
         network: Network? = null
-    ): Pair<WorkResult, VerifyStatus> {
+    ): Triple<WorkResult, VerifyStatus, Statement?> {
         var exception: Exception? = null
         val resultAndStatus = try {
             val sourceAsset = StatementUtils.createWebAssetString(host)
                 .let(AbstractAsset::create)
             val result = retriever.retrieve(sourceAsset, network)
-                ?: return WorkResult.success() to VerifyStatus.FAILURE_UNKNOWN
+                ?: return Triple(WorkResult.success(), VerifyStatus.FAILURE_UNKNOWN, null)
             when (result.responseCode) {
                 HttpURLConnection.HTTP_MOVED_PERM,
                 HttpURLConnection.HTTP_MOVED_TEMP -> {
-                    WorkResult.failure() to VerifyStatus.FAILURE_REDIRECT
+                    Triple(WorkResult.failure(), VerifyStatus.FAILURE_REDIRECT, null)
                 }
                 else -> {
-                    val isVerified = result.statements.any { statement ->
+                    val statement = result.statements.firstOrNull { statement ->
                         (StatementUtils.RELATION.matches(statement.relation) &&
                                 assetMatcher.matches(statement.target))
                     }
 
-                    if (isVerified) {
-                        WorkResult.success() to VerifyStatus.SUCCESS
+                    if (statement != null) {
+                        Triple(WorkResult.success(), VerifyStatus.SUCCESS, statement)
                     } else {
-                        WorkResult.failure() to VerifyStatus.FAILURE_REJECTED_BY_SERVER
+                        Triple(WorkResult.failure(), VerifyStatus.FAILURE_REJECTED_BY_SERVER, statement)
                     }
                 }
             }
         } catch (e: Exception) {
             exception = e
-            WorkResult.retry() to VerifyStatus.FAILURE_UNKNOWN
+            Triple(WorkResult.retry(), VerifyStatus.FAILURE_UNKNOWN, null)
         }
 
         if (DEBUG) {
diff --git a/packages/StatementService/src/com/android/statementservice/domain/VerifyStatus.kt b/packages/StatementService/src/com/android/statementservice/domain/VerifyStatus.kt
index 2193ec5..c771da3 100644
--- a/packages/StatementService/src/com/android/statementservice/domain/VerifyStatus.kt
+++ b/packages/StatementService/src/com/android/statementservice/domain/VerifyStatus.kt
@@ -49,7 +49,7 @@
                 return false
             }
 
-            val status = values().find { it.value == state } ?: return true
+            val status = entries.find { it.value == state } ?: return true
             return when (status) {
                 SUCCESS,
                 FAILURE_LEGACY_UNSUPPORTED_WILDCARD,
@@ -62,5 +62,20 @@
                 FAILURE_REDIRECT -> true
             }
         }
+
+        fun canUpdate(state: Int): Boolean {
+            if (state == DomainVerificationInfo.STATE_UNMODIFIABLE) {
+                return false
+            }
+
+            val status = entries.find { it.value == state }
+            return when (status) {
+                SUCCESS,
+                FAILURE_LEGACY_UNSUPPORTED_WILDCARD,
+                FAILURE_REJECTED_BY_SERVER,
+                UNKNOWN -> true
+                else -> false
+            }
+        }
     }
 }
diff --git a/packages/StatementService/src/com/android/statementservice/domain/worker/BaseRequestWorker.kt b/packages/StatementService/src/com/android/statementservice/domain/worker/BaseRequestWorker.kt
index a17f9c9..64d2d98 100644
--- a/packages/StatementService/src/com/android/statementservice/domain/worker/BaseRequestWorker.kt
+++ b/packages/StatementService/src/com/android/statementservice/domain/worker/BaseRequestWorker.kt
@@ -17,9 +17,12 @@
 package com.android.statementservice.domain.worker
 
 import android.content.Context
+import android.content.UriRelativeFilterGroup
+import android.content.pm.verify.domain.DomainVerificationInfo
 import android.content.pm.verify.domain.DomainVerificationManager
 import androidx.work.CoroutineWorker
 import androidx.work.WorkerParameters
+import com.android.statementservice.database.DomainGroupsDatabase
 import com.android.statementservice.domain.DomainVerifier
 
 abstract class BaseRequestWorker(
@@ -27,8 +30,19 @@
     protected val params: WorkerParameters
 ) : CoroutineWorker(appContext, params) {
 
+    protected val database = DomainGroupsDatabase.getInstance(appContext).domainGroupsDao()
+
     protected val verificationManager =
         appContext.getSystemService(DomainVerificationManager::class.java)!!
 
     protected val verifier = DomainVerifier.getInstance(appContext)
+
+    protected fun updateUriRelativeFilterGroups(packageName: String, domainGroupUpdates: Map<String, List<UriRelativeFilterGroup>>) {
+        val verifiedDomains = verificationManager.getDomainVerificationInfo(packageName)?.hostToStateMap?.filterValues {
+            it == DomainVerificationInfo.STATE_SUCCESS || it == DomainVerificationInfo.STATE_MODIFIABLE_VERIFIED
+        }?.keys?.toList() ?: emptyList()
+        val domainGroups = verificationManager.getUriRelativeFilterGroups(packageName, verifiedDomains)
+        domainGroupUpdates.forEach { (domain, groups) -> domainGroups[domain] = groups }
+        verificationManager.setUriRelativeFilterGroups(packageName, domainGroups)
+    }
 }
diff --git a/packages/StatementService/src/com/android/statementservice/domain/worker/GroupUpdateV1Worker.kt b/packages/StatementService/src/com/android/statementservice/domain/worker/GroupUpdateV1Worker.kt
new file mode 100644
index 0000000..f53dfc4
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/domain/worker/GroupUpdateV1Worker.kt
@@ -0,0 +1,55 @@
+/*
+ * 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.statementservice.domain.worker
+
+import android.content.Context
+import androidx.work.Data
+import androidx.work.OneTimeWorkRequestBuilder
+import androidx.work.WorkerParameters
+import kotlinx.coroutines.coroutineScope
+
+class GroupUpdateV1Worker(appContext: Context, params: WorkerParameters) :
+    BaseRequestWorker(appContext, params) {
+
+    companion object {
+
+        private const val PACKAGE_NAME_KEY = "packageName"
+
+        fun buildRequest(packageName: String) = OneTimeWorkRequestBuilder<GroupUpdateV1Worker>()
+            .setInputData(
+                Data.Builder()
+                    .putString(PACKAGE_NAME_KEY, packageName)
+                    .build()
+            )
+            .build()
+    }
+
+    override suspend fun doWork() = coroutineScope {
+        val packageName = params.inputData.getString(PACKAGE_NAME_KEY)!!
+        updateUriRelativeFilterGroups(packageName)
+        Result.success()
+    }
+
+    private fun updateUriRelativeFilterGroups(packageName: String) {
+        val groupUpdates = database.getDomainGroups(packageName)
+        updateUriRelativeFilterGroups(
+            packageName,
+            groupUpdates.associateBy({it.domain}, {it.groups})
+        )
+        database.clear(packageName)
+    }
+}
\ No newline at end of file
diff --git a/packages/StatementService/src/com/android/statementservice/domain/worker/PeriodicUpdateWorker.kt b/packages/StatementService/src/com/android/statementservice/domain/worker/PeriodicUpdateWorker.kt
new file mode 100644
index 0000000..7ec6e6c
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/domain/worker/PeriodicUpdateWorker.kt
@@ -0,0 +1,94 @@
+/*
+ * 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.statementservice.domain.worker
+
+import android.content.Context
+import android.content.UriRelativeFilterGroup
+import android.content.pm.verify.domain.DomainVerificationManager
+import androidx.work.ListenableWorker
+import androidx.work.WorkerParameters
+import com.android.statementservice.domain.VerifyStatus
+import com.android.statementservice.utils.AndroidUtils
+import com.android.statementservice.utils.StatementUtils
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.isActive
+
+abstract class PeriodicUpdateWorker(
+    appContext: Context,
+    params: WorkerParameters
+) : BaseRequestWorker(appContext, params) {
+
+    data class VerifyResult(
+        val host: String,
+        val status: VerifyStatus,
+        val groups: List<UriRelativeFilterGroup>
+    )
+
+    protected suspend fun updateDomainVerificationStatus(verifyStatusFilter: (Int) -> Boolean):
+            ListenableWorker.Result {
+        return coroutineScope {
+            if (!AndroidUtils.isReceiverV2Enabled(appContext)) {
+                return@coroutineScope Result.success()
+            }
+
+            val packageNames = verificationManager.queryValidVerificationPackageNames()
+
+            verifier.collectHosts(packageNames, verifyStatusFilter)
+                .map { (domainSetId, packageName, hosts) ->
+                    hosts.map { host ->
+                        async {
+                            if (isActive && !isStopped) {
+                                val (_, status, statement) = verifier.verifyHost(
+                                    host,
+                                    packageName,
+                                    params.network
+                                )
+                                val groups = statement?.dynamicAppLinkComponents.orEmpty().map {
+                                    StatementUtils.createUriRelativeFilterGroup(it)
+                                }
+                                VerifyResult(host, status, groups)
+                            } else {
+                                // If the job gets cancelled, stop the remaining hosts, but continue the
+                                // job to commit the results for hosts that were already requested.
+                                null
+                            }
+                        }
+                    }.awaitAll().filterNotNull().groupBy { it.status }
+                        .forEach { (status, results) ->
+                            val error = verificationManager.setDomainVerificationStatus(
+                                domainSetId,
+                                results.map { it.host }.toSet(),
+                                status.value
+                            )
+                            if (error == DomainVerificationManager.STATUS_OK
+                                && status == VerifyStatus.SUCCESS
+                            ) {
+                                updateUriRelativeFilterGroups(
+                                    packageName,
+                                    results.associateBy({ it.host }, { it.groups })
+                                )
+                            }
+                        }
+                }
+
+            // Succeed regardless of results since this retry is best effort and not required
+            Result.success()
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/StatementService/src/com/android/statementservice/domain/worker/RetryRequestWorker.kt b/packages/StatementService/src/com/android/statementservice/domain/worker/RetryRequestWorker.kt
index 61ab2c2..e8b4df9 100644
--- a/packages/StatementService/src/com/android/statementservice/domain/worker/RetryRequestWorker.kt
+++ b/packages/StatementService/src/com/android/statementservice/domain/worker/RetryRequestWorker.kt
@@ -20,12 +20,6 @@
 import androidx.work.NetworkType
 import androidx.work.WorkerParameters
 import com.android.statementservice.domain.VerifyStatus
-import com.android.statementservice.utils.AndroidUtils
-import kotlinx.coroutines.async
-import kotlinx.coroutines.awaitAll
-import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.isActive
-import java.util.UUID
 
 /**
  * Scheduled every 24 hours with [NetworkType.CONNECTED] and every 72 hours without any constraints
@@ -34,46 +28,7 @@
 class RetryRequestWorker(
     appContext: Context,
     params: WorkerParameters
-) : BaseRequestWorker(appContext, params) {
+) : PeriodicUpdateWorker(appContext, params) {
 
-    data class VerifyResult(val domainSetId: UUID, val host: String, val status: VerifyStatus)
-
-    override suspend fun doWork() = coroutineScope {
-        if (!AndroidUtils.isReceiverV2Enabled(appContext)) {
-            return@coroutineScope Result.success()
-        }
-
-        val packageNames = verificationManager.queryValidVerificationPackageNames()
-
-        verifier.collectHosts(packageNames)
-            .map { (domainSetId, packageName, host) ->
-                async {
-                    if (isActive && !isStopped) {
-                        val (_, status) = verifier.verifyHost(host, packageName, params.network)
-                        VerifyResult(domainSetId, host, status)
-                    } else {
-                        // If the job gets cancelled, stop the remaining hosts, but continue the
-                        // job to commit the results for hosts that were already requested.
-                        null
-                    }
-                }
-            }
-            .awaitAll()
-            .filterNotNull() // TODO(b/159952358): Fast fail packages which can't be retrieved.
-            .groupBy { it.domainSetId }
-            .forEach { (domainSetId, resultsById) ->
-                resultsById.groupBy { it.status }
-                    .mapValues { it.value.map(VerifyResult::host).toSet() }
-                    .forEach { (status, hosts) ->
-                        verificationManager.setDomainVerificationStatus(
-                            domainSetId,
-                            hosts,
-                            status.value
-                        )
-                    }
-            }
-
-        // Succeed regardless of results since this retry is best effort and not required
-        Result.success()
-    }
+    override suspend fun doWork() = updateDomainVerificationStatus(VerifyStatus::shouldRetry)
 }
diff --git a/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV1RequestWorker.kt b/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV1RequestWorker.kt
index 7a198cb..253a162 100644
--- a/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV1RequestWorker.kt
+++ b/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV1RequestWorker.kt
@@ -22,7 +22,9 @@
 import androidx.work.OneTimeWorkRequest
 import androidx.work.OneTimeWorkRequestBuilder
 import androidx.work.WorkerParameters
+import com.android.statementservice.database.DomainGroups
 import com.android.statementservice.utils.AndroidUtils
+import com.android.statementservice.utils.StatementUtils
 import kotlinx.coroutines.coroutineScope
 
 class SingleV1RequestWorker(appContext: Context, params: WorkerParameters) :
@@ -60,7 +62,9 @@
         val packageName = params.inputData.getString(PACKAGE_NAME_KEY)!!
         val host = params.inputData.getString(HOST_KEY)!!
 
-        val (result, status) = verifier.verifyHost(host, packageName, params.network)
+        database.clear(packageName, host)
+
+        val (result, status, statement) = verifier.verifyHost(host, packageName, params.network)
 
         if (DEBUG) {
             Log.d(
@@ -75,6 +79,10 @@
                 val deContext = appContext.createDeviceProtectedStorageContext()
                 val sp = deContext?.getSharedPreferences(packageName, Context.MODE_PRIVATE)
                 sp?.edit()?.putInt("$HOST_SUCCESS_PREFIX$host", status.value)?.apply()
+                val groups = statement?.dynamicAppLinkComponents.orEmpty().map {
+                    StatementUtils.createUriRelativeFilterGroup(it)
+                }
+                database.insertDomainGroups(DomainGroups(packageName, host, groups))
                 Result.success()
             }
             is Result.Failure -> {
diff --git a/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV2RequestWorker.kt b/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV2RequestWorker.kt
index 562b132..8b1347a 100644
--- a/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV2RequestWorker.kt
+++ b/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV2RequestWorker.kt
@@ -22,6 +22,7 @@
 import androidx.work.OneTimeWorkRequestBuilder
 import androidx.work.WorkerParameters
 import com.android.statementservice.utils.AndroidUtils
+import com.android.statementservice.utils.StatementUtils
 import kotlinx.coroutines.coroutineScope
 import java.util.UUID
 
@@ -59,9 +60,13 @@
         val packageName = params.inputData.getString(PACKAGE_NAME_KEY)!!
         val host = params.inputData.getString(HOST_KEY)!!
 
-        val (result, status) = verifier.verifyHost(host, packageName, params.network)
+        val (result, status, statement) = verifier.verifyHost(host, packageName, params.network)
 
         verificationManager.setDomainVerificationStatus(domainSetId, setOf(host), status.value)
+        val groups = statement?.dynamicAppLinkComponents.orEmpty().map {
+            StatementUtils.createUriRelativeFilterGroup(it)
+        }
+        updateUriRelativeFilterGroups(packageName, mapOf(host to groups))
 
         result
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt b/packages/StatementService/src/com/android/statementservice/domain/worker/UpdateVerifiedDomainsWorker.kt
similarity index 60%
copy from packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
copy to packages/StatementService/src/com/android/statementservice/domain/worker/UpdateVerifiedDomainsWorker.kt
index 83551e9..c6f40c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
+++ b/packages/StatementService/src/com/android/statementservice/domain/worker/UpdateVerifiedDomainsWorker.kt
@@ -14,15 +14,16 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.phone
+package com.android.statementservice.domain.worker
 
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.policy.BaseHeadsUpManager
-import com.android.systemui.statusbar.policy.HeadsUpManager
-import dagger.Binds
-import dagger.Module
+import android.content.Context
+import androidx.work.WorkerParameters
+import com.android.statementservice.domain.VerifyStatus
 
-@Module
-interface HeadsUpModule {
-    @Binds @SysUISingleton fun bindsHeadsUpManager(hum: BaseHeadsUpManager): HeadsUpManager
-}
+class UpdateVerifiedDomainsWorker(
+    appContext: Context,
+    params: WorkerParameters
+) : PeriodicUpdateWorker(appContext, params) {
+
+    override suspend fun doWork() = updateDomainVerificationStatus(VerifyStatus::canUpdate)
+}
\ No newline at end of file
diff --git a/packages/StatementService/src/com/android/statementservice/network/retriever/StatementParser.kt b/packages/StatementService/src/com/android/statementservice/network/retriever/StatementParser.kt
index ad137400..d10cb0f 100644
--- a/packages/StatementService/src/com/android/statementservice/network/retriever/StatementParser.kt
+++ b/packages/StatementService/src/com/android/statementservice/network/retriever/StatementParser.kt
@@ -39,6 +39,11 @@
 
     private const val FIELD_NOT_STRING_FORMAT_STRING = "Expected %s to be string."
     private const val FIELD_NOT_ARRAY_FORMAT_STRING = "Expected %s to be array."
+    private const val COMMENTS_NAME = "comments"
+    private const val EXCLUDE_NAME = "exclude"
+    private const val FRAGMENT_NAME = "#"
+    private const val QUERY_NAME = "?"
+    private const val PATH_NAME = "/"
 
     /**
      * Parses a JSON array of statements.
@@ -99,9 +104,7 @@
                 FIELD_NOT_ARRAY_FORMAT_STRING.format(StatementUtils.ASSET_DESCRIPTOR_FIELD_RELATION)
             )
         val target = AssetFactory.create(targetObject)
-        val dynamicAppLinkComponents = parseDynamicAppLinkComponents(
-            statement.optJSONObject(StatementUtils.ASSET_DESCRIPTOR_FIELD_RELATION_EXTENSIONS)
-        )
+        val dynamicAppLinkComponents = parseDynamicAppLinkComponents(statement)
 
         val statements = (0 until relations.length())
             .map { relations.getString(it) }
@@ -129,13 +132,13 @@
     }
 
     private fun parseComponent(component: JSONObject): DynamicAppLinkComponent {
-        val query = component.optJSONObject("?")
+        val query = component.optJSONObject(QUERY_NAME)
         return DynamicAppLinkComponent.create(
-            component.optBoolean("exclude", false),
-            component.optString("#"),
-            component.optString("/"),
+            component.optBoolean(EXCLUDE_NAME, false),
+            if (component.has(FRAGMENT_NAME)) component.getString(FRAGMENT_NAME) else null,
+            if (component.has(PATH_NAME)) component.getString(PATH_NAME) else null,
             query?.keys()?.asSequence()?.associateWith { query.getString(it) },
-            component.optString("comments")
+            component.optString(COMMENTS_NAME)
         )
     }
 
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/DynamicAppLinkComponent.java b/packages/StatementService/src/com/android/statementservice/retriever/DynamicAppLinkComponent.java
index dc27e12..c32f194 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/DynamicAppLinkComponent.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/DynamicAppLinkComponent.java
@@ -130,7 +130,7 @@
     @Override
     public String toString() {
         StringBuilder statement = new StringBuilder();
-        statement.append("HandleAllUriRule: ");
+        statement.append("DynamicAppLinkComponent: ");
         statement.append(mExclude);
         statement.append(", ");
         statement.append(mFragment);
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/JsonParser.java b/packages/StatementService/src/com/android/statementservice/retriever/JsonParser.java
index 7635e82..ab1853c 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/JsonParser.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/JsonParser.java
@@ -24,8 +24,6 @@
 import org.json.JSONObject;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
 
 /**
  * A helper class that creates a {@link JSONObject} from a {@link JsonReader}.
@@ -48,7 +46,7 @@
 
             JsonToken token = reader.peek();
             if (token.equals(JsonToken.BEGIN_ARRAY)) {
-                output.put(fieldName, new JSONArray(parseArray(reader)));
+                output.put(fieldName, parseArray(reader));
             } else if (token.equals(JsonToken.STRING)) {
                 output.put(fieldName, reader.nextString());
             } else if (token.equals(JsonToken.BEGIN_OBJECT)) {
@@ -57,9 +55,11 @@
                 } catch (JSONException e) {
                     errorMsg = e.getMessage();
                 }
+            } else if (token.equals(JsonToken.BOOLEAN)) {
+                output.put(fieldName, reader.nextBoolean());
             } else {
                 reader.skipValue();
-                errorMsg = "Unsupported value type.";
+                errorMsg = "Unsupported value type: " + token;
             }
         }
         reader.endObject();
@@ -72,17 +72,36 @@
     }
 
     /**
-     * Parses one string array from the {@link JsonReader}.
+     * Parses one JSON array from the {@link JsonReader}.
      */
-    public static List<String> parseArray(JsonReader reader) throws IOException {
-        ArrayList<String> output = new ArrayList<>();
+    public static JSONArray parseArray(JsonReader reader) throws IOException, JSONException {
+        JSONArray output = new JSONArray();
+        String errorMsg = null;
 
         reader.beginArray();
         while (reader.hasNext()) {
-            output.add(reader.nextString());
+            JsonToken token = reader.peek();
+            if (token.equals(JsonToken.BEGIN_ARRAY)) {
+                output.put(parseArray(reader));
+            } else if (token.equals(JsonToken.STRING)) {
+                output.put(reader.nextString());
+            } else if (token.equals(JsonToken.BEGIN_OBJECT)) {
+                try {
+                    output.put(parse(reader));
+                } catch (JSONException e) {
+                    errorMsg = e.getMessage();
+                }
+            } else {
+                reader.skipValue();
+                errorMsg = "Unsupported value type: " + token;
+            }
         }
         reader.endArray();
 
+        if (errorMsg != null) {
+            throw new JSONException(errorMsg);
+        }
+
         return output;
     }
 }
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index d1a22e8..3d250fd 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -81,33 +81,37 @@
     visibility: ["//visibility:private"],
 }
 
-// Tests where robolectric conversion caused errors in SystemUITests at runtime
-filegroup {
-    name: "SystemUI-tests-broken-robofiles-sysui-run",
-    srcs: [
-        "tests/src/**/systemui/broadcast/BroadcastDispatcherTest.kt",
-        "tests/src/**/systemui/broadcast/ActionReceiverTest.kt",
-        "tests/src/**/systemui/globalactions/GlobalActionsDialogLiteTest.java",
-        "tests/src/**/systemui/globalactions/GlobalActionsImeTest.java",
-        "tests/src/**/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt",
-        "tests/src/**/systemui/media/dialog/MediaOutputAdapterTest.java",
-        "tests/src/**/systemui/media/dialog/MediaOutputBaseDialogTest.java",
-        "tests/src/**/systemui/media/dialog/MediaOutputBroadcastDialogTest.java",
-        "tests/src/**/systemui/media/dialog/MediaOutputDialogTest.java",
-        "tests/src/**/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegateTest.kt",
-        "tests/src/**/systemui/settings/brightness/BrightnessDialogTest.kt",
-    ],
-}
-
 // Tests where robolectric failed at runtime. (go/central-multivalent)
 filegroup {
     name: "SystemUI-tests-broken-robofiles-run",
     srcs: [
-        "tests/src/**/systemui/ExpandHelperTest.java",
+        "tests/src/**/systemui/shade/NotificationShadeWindowViewControllerTest.kt",
+        "tests/src/**/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt",
+        "tests/src/**/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt",
+        "tests/src/**/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt",
+        "tests/src/**/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt",
+        "tests/src/**/systemui/animation/back/FlingOnBackAnimationCallbackTest.kt",
+        "tests/src/**/systemui/education/domain/ui/view/ContextualEduDialogTest.kt",
+        "tests/src/**/systemui/screenshot/ActionIntentCreatorTest.kt",
+        "tests/src/**/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt",
+        "tests/src/**/systemui/accessibility/WindowMagnificationControllerTest.java",
+        "tests/src/**/systemui/broadcast/BroadcastDispatcherTest.kt",
+        "tests/src/**/systemui/globalactions/GlobalActionsDialogLiteTest.java",
+        "tests/src/**/systemui/globalactions/GlobalActionsImeTest.java",
+        "tests/src/**/systemui/media/dialog/MediaOutputBaseDialogTest.java",
+        "tests/src/**/systemui/media/dialog/MediaOutputBroadcastDialogTest.java",
+        "tests/src/**/systemui/media/dialog/MediaOutputDialogTest.java",
+        "tests/src/**/systemui/settings/brightness/BrightnessDialogTest.kt",
+        "tests/src/**/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt",
+        "tests/src/**/systemui/statusbar/policy/SecurityControllerTest.java",
+        "tests/src/**/systemui/lifecycle/SysUiViewModelTest.kt",
+        "tests/src/**/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt",
+        "tests/src/**/systemui/graphics/ImageLoaderContentProviderTest.kt",
+        "tests/src/**/systemui/flags/FakeFeatureFlagsTest.kt",
+        "tests/src/**/systemui/communal/data/backup/CommunalBackupUtilsTest.kt",
         "tests/src/**/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java",
         "tests/src/**/systemui/accessibility/AccessibilityGestureTargetsObserverTest.java",
         "tests/src/**/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java",
-        "tests/src/**/systemui/accessibility/floatingmenu/AccessibilityTargetAdapterTest.java",
         "tests/src/**/systemui/screenshot/appclips/AppClipsActivityTest.java",
         "tests/src/**/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java",
         "tests/src/**/systemui/screenshot/appclips/AppClipsViewModelTest.java",
@@ -124,36 +128,27 @@
         "tests/src/**/systemui/classifier/FalsingDataProviderTest.java",
         "tests/src/**/systemui/screenshot/ImageExporterTest.java",
         "tests/src/**/systemui/bouncer/data/repository/KeyguardBouncerRepositoryTest.kt",
-        "tests/src/**/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt",
         "tests/src/**/systemui/logcat/LogAccessDialogActivityTest.java",
         "tests/src/**/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt",
         "tests/src/**/systemui/media/controls/domain/pipeline/MediaSessionBasedFilterTest.kt",
         "tests/src/**/systemui/accessibility/floatingmenu/MenuNotificationFactoryTest.java",
         "tests/src/**/systemui/accessibility/floatingmenu/MenuViewLayerTest.java",
-        "tests/src/**/systemui/accessibility/floatingmenu/MenuViewTest.java",
         "tests/src/**/systemui/classifier/PointerCountClassifierTest.java",
         "tests/src/**/systemui/accessibility/floatingmenu/RadiiAnimatorTest.java",
         "tests/src/**/systemui/screenrecord/RecordingControllerTest.java",
         "tests/src/**/systemui/screenshot/RequestProcessorTest.kt",
         "tests/src/**/systemui/media/controls/domain/resume/ResumeMediaBrowserTest.kt",
-        "tests/src/**/systemui/screenshot/SaveImageInBackgroundTaskTest.kt",
         "tests/src/**/systemui/screenshot/scroll/ScrollCaptureClientTest.java",
         "tests/src/**/systemui/accessibility/SecureSettingsContentObserverTest.java",
         "tests/src/**/systemui/media/controls/ui/viewmodel/SeekBarViewModelTest.kt",
         "tests/src/**/systemui/qs/external/TileServicesTest.java",
         "tests/src/**/systemui/ambient/touch/TouchMonitorTest.java",
-        "tests/src/**/systemui/accessibility/WindowMagnificationControllerWindowlessMagnifierTest.java",
         "tests/src/**/systemui/accessibility/WindowMagnificationSettingsTest.java",
-        "tests/src/androidx/core/animation/AnimatorTestRuleIsolationTest.kt",
         "tests/src/**/systemui/CameraProtectionLoaderImplTest.kt",
-        "tests/src/**/systemui/DependencyTest.java",
-        "tests/src/**/systemui/InitControllerTest.java",
         "tests/src/**/systemui/SliceBroadcastRelayHandlerTest.java",
         "tests/src/**/systemui/SystemUIApplicationTest.kt",
         "tests/src/**/systemui/SysUICutoutProviderTest.kt",
-        "tests/src/**/keyguard/ActiveUnlockConfigTest.kt",
         "tests/src/**/keyguard/AdminSecondaryLockScreenControllerTest.java",
-        "tests/src/**/keyguard/KeyguardClockAccessibilityDelegateTest.java",
         "tests/src/**/keyguard/KeyguardStatusViewControllerTest.java",
         "tests/src/**/systemui/accessibility/AccessibilityButtonModeObserverTest.java",
         "tests/src/**/systemui/accessibility/AccessibilityButtonTargetsObserverTest.java",
@@ -164,16 +159,12 @@
         "tests/src/**/systemui/animation/TextAnimatorTest.kt",
         "tests/src/**/systemui/animation/TextInterpolatorTest.kt",
         "tests/src/**/systemui/animation/ActivityTransitionAnimatorTest.kt",
-        "tests/src/**/systemui/animation/AnimatorTestRuleOrderTest.kt",
         "tests/src/**/systemui/animation/DialogTransitionAnimatorTest.kt",
-        "tests/src/**/systemui/broadcast/ActionReceiverTest.kt",
         "tests/src/**/systemui/broadcast/BroadcastDispatcherTest.kt",
-        "tests/src/**/systemui/compose/ComposeInitializerTest.kt",
         "tests/src/**/systemui/controls/ui/ControlsActivityTest.kt",
         "tests/src/**/systemui/controls/management/ControlsEditingActivityTest.kt",
         "tests/src/**/systemui/controls/management/ControlsRequestDialogTest.kt",
         "tests/src/**/systemui/controls/ui/DetailDialogTest.kt",
-        "tests/src/**/systemui/fontscaling/FontScalingDialogDelegateTest.kt",
         "tests/src/**/systemui/keyguard/CustomizationProviderTest.kt",
         "tests/src/**/systemui/globalactions/GlobalActionsColumnLayoutTest.java",
         "tests/src/**/systemui/globalactions/GlobalActionsDialogLiteTest.java",
@@ -182,10 +173,6 @@
         "tests/src/**/systemui/keyguard/CustomizationProviderTest.kt",
         "tests/src/**/systemui/keyguard/KeyguardViewMediatorTest.java",
         "tests/src/**/systemui/keyguard/LifecycleTest.java",
-        "tests/src/**/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt",
-        "tests/src/**/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt",
-        "tests/src/**/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt",
-        "tests/src/**/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelTest.kt",
         "tests/src/**/systemui/lifecycle/RepeatWhenAttachedTest.kt",
         "tests/src/**/systemui/log/LogBufferTest.kt",
         "tests/src/**/systemui/media/dialog/MediaOutputBaseDialogTest.java",
@@ -193,52 +180,35 @@
         "tests/src/**/systemui/media/dialog/MediaOutputDialogTest.java",
         "tests/src/**/systemui/media/controls/domain/resume/MediaResumeListenerTest.kt",
         "tests/src/**/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinatorTest.kt",
-        "tests/src/**/systemui/navigationbar/views/NavigationBarButtonTest.java",
         "tests/src/**/systemui/people/PeopleProviderTest.java",
         "tests/src/**/systemui/people/PeopleSpaceUtilsTest.java",
         "tests/src/**/systemui/people/widget/PeopleSpaceWidgetManagerTest.java",
         "tests/src/**/systemui/people/PeopleTileViewHelperTest.java",
         "tests/src/**/systemui/power/data/repository/PowerRepositoryImplTest.kt",
-        "tests/src/**/systemui/privacy/PrivacyConfigFlagsTest.kt",
-        "tests/src/**/systemui/privacy/PrivacyDialogV2Test.kt",
-        "tests/src/**/systemui/qs/external/TileRequestDialogEventLoggerTest.kt",
-        "tests/src/**/systemui/qs/AutoAddTrackerTest.kt",
-        "tests/src/**/systemui/qs/external/TileRequestDialogEventLoggerTest.kt",
         "tests/src/**/systemui/qs/tiles/DndTileTest.kt",
         "tests/src/**/systemui/qs/tiles/DreamTileTest.java",
-        "tests/src/**/systemui/qs/FgsManagerControllerTest.java",
         "tests/src/**/systemui/qs/QSPanelTest.kt",
         "tests/src/**/systemui/reardisplay/RearDisplayCoreStartableTest.kt",
         "tests/src/**/systemui/reardisplay/RearDisplayDialogControllerTest.java",
         "tests/src/**/systemui/reardisplay/RearDisplayInnerDialogDelegateTest.kt",
         "tests/src/**/systemui/statusbar/KeyboardShortcutListSearchTest.java",
         "tests/src/**/systemui/statusbar/KeyboardShortcutsTest.java",
-        "tests/src/**/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt",
-        "tests/src/**/systemui/statusbar/notification/AssistantFeedbackControllerTest.java",
         "tests/src/**/systemui/statusbar/notification/collection/NotificationEntryTest.java",
-        "tests/src/**/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt",
         "tests/src/**/systemui/statusbar/notification/collection/ShadeListBuilderTest.java",
-        "tests/src/**/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java",
         "tests/src/**/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java",
         "tests/src/**/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt",
         "tests/src/**/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt",
-        "tests/src/**/systemui/statusbar/NotificationLockscreenUserManagerTest.java",
         "tests/src/**/systemui/statusbar/notification/logging/NotificationLoggerTest.java",
         "tests/src/**/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java",
-        "tests/src/**/systemui/statusbar/notification/row/NotificationContentInflaterTest.java",
         "tests/src/**/systemui/statusbar/notification/row/NotificationContentViewTest.kt",
         "tests/src/**/systemui/statusbar/notification/row/NotificationConversationInfoTest.java",
-        "tests/src/**/systemui/statusbar/notification/row/NotificationGutsManagerTest.java",
         "tests/src/**/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt",
         "tests/src/**/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt",
         "tests/src/**/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java",
-        "tests/src/**/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt",
-        "tests/src/**/systemui/statusbar/phone/AutoTileManagerTest.java",
         "tests/src/**/systemui/statusbar/phone/CentralSurfacesImplTest.java",
         "tests/src/**/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java",
         "tests/src/**/systemui/statusbar/phone/PhoneStatusBarTransitionsTest.kt",
         "tests/src/**/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt",
-        "tests/src/**/systemui/statusbar/phone/PhoneStatusBarView.java",
         "tests/src/**/systemui/statusbar/phone/PhoneStatusBarViewTest.kt",
         "tests/src/**/systemui/statusbar/phone/StatusBarBoundsProviderTest.kt",
         "tests/src/**/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt",
@@ -252,13 +222,9 @@
         "tests/src/**/systemui/statusbar/policy/LocationControllerImplTest.java",
         "tests/src/**/systemui/statusbar/policy/RemoteInputViewTest.java",
         "tests/src/**/systemui/statusbar/policy/SmartReplyViewTest.java",
-        "tests/src/**/systemui/statusbar/policy/ui/dialog/ModesDialogDelegateTest.kt",
-        "tests/src/**/systemui/statusbar/StatusBarStateControllerImplTest.kt",
         "tests/src/**/systemui/theme/ThemeOverlayApplierTest.java",
         "tests/src/**/systemui/touch/TouchInsetManagerTest.java",
         "tests/src/**/systemui/util/LifecycleFragmentTest.java",
-        "tests/src/**/systemui/util/kotlin/PairwiseFlowTest",
-        "tests/src/**/systemui/util/sensors/AsyncManagerTest.java",
         "tests/src/**/systemui/util/sensors/ThresholdSensorImplTest.java",
         "tests/src/**/systemui/volume/VolumeDialogImplTest.java",
         "tests/src/**/systemui/wallet/controller/QuickAccessWalletControllerTest.java",
@@ -271,26 +237,17 @@
         "tests/src/**/systemui/clipboardoverlay/ClipboardListenerTest.java",
         "tests/src/**/systemui/communal/data/db/CommunalDatabaseMigrationsTest.kt",
         "tests/src/**/systemui/communal/data/db/CommunalWidgetDaoTest.kt",
-        "tests/src/**/systemui/display/data/repository/DisplayWindowPropertiesRepositoryImplTest.kt",
         "tests/src/**/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt",
         "tests/src/**/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt",
         "tests/src/**/systemui/lifecycle/ActivatableTest.kt",
-        "tests/src/**/systemui/lifecycle/HydratorTest.kt",
         "tests/src/**/systemui/media/dialog/MediaSwitchingControllerTest.java",
         "tests/src/**/systemui/qs/QSImplTest.java",
         "tests/src/**/systemui/qs/panels/ui/compose/DragAndDropTest.kt",
         "tests/src/**/systemui/qs/panels/ui/compose/ResizingTest.kt",
         "tests/src/**/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java",
-        "tests/src/**/systemui/accessibility/floatingmenu/PositionTest.java",
         "tests/src/**/systemui/animation/TransitionAnimatorTest.kt",
-        "tests/src/**/systemui/screenshot/scroll/ScrollCaptureControllerTest.java",
-        "tests/src/**/systemui/lifecycle/SysuiViewModelTest.kt",
-        "tests/src/**/systemui/flags/FakeFeatureFlags.kt",
         "tests/src/**/systemui/animation/TransitionAnimatorTest.kt",
-        "tests/src/**/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java",
         "tests/src/**/systemui/statusbar/connectivity/NetworkControllerSignalTest.java",
-        "tests/src/**/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt",
-        "tests/src/**/systemui/statusbar/policy/RotationLockControllerImplTest.java",
         "tests/src/**/systemui/statusbar/phone/ScrimControllerTest.java",
         "tests/src/**/systemui/toast/ToastUITest.java",
         "tests/src/**/systemui/statusbar/policy/FlashlightControllerImplTest.kt",
@@ -329,47 +286,48 @@
         "tests/src/**/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java",
         "tests/src/**/systemui/qs/external/TileLifecycleManagerTest.java",
         "tests/src/**/systemui/ScreenDecorationsTest.java",
+        "tests/src/**/systemui/statusbar/policy/BatteryControllerStartableTest.java",
         "tests/src/**/keyguard/CarrierTextManagerTest.java",
         "tests/src/**/keyguard/KeyguardUpdateMonitorTest.java",
     ],
 }
 
-// Tests where robolectric failed at compile time. (go/multivalent-tests)
+// Tests where compilation failed due to kotlin internal references.
 filegroup {
-    name: "SystemUI-tests-broken-robofiles-compile",
+    name: "SystemUI-tests-broken-robofiles-internal",
     srcs: [
-        "tests/src/**/systemui/statusbar/notification/icon/IconManagerTest.kt",
-        "tests/src/**/systemui/statusbar/KeyguardIndicationControllerTest.java",
-        "tests/src/**/systemui/doze/DozeScreenStateTest.java",
-        "tests/src/**/systemui/notetask/NoteTaskInitializerTest.kt",
-        "tests/src/**/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt",
-        "tests/src/**/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt",
-        "tests/src/**/systemui/controls/management/ControlsFavoritingActivityTest.kt",
-        "tests/src/**/systemui/controls/management/ControlsProviderSelectorActivityTest.kt",
-        "tests/src/**/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt",
-        "tests/src/**/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt",
-        "tests/src/**/systemui/qs/tileimpl/QSTileViewImplTest.kt",
+        "tests/src/**/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt",
+        "tests/src/**/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt",
+        "tests/src/**/android/systemui/statusbar/notification/icon/IconManagerTest.kt",
+        "tests/src/**/android/systemui/notetask/NoteTaskInitializerTest.kt",
+        "tests/src/**/systemui/statusbar/policy/VariableDateViewControllerTest.kt",
+        "tests/src/**/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt",
+        "tests/src/**/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt",
+        "tests/src/**/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt",
+        "tests/src/**/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt",
+        "tests/src/**/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt",
         "tests/src/**/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt",
+        "tests/src/**/systemui/statusbar/policy/WalletControllerImplTest.kt",
         "tests/src/**/keyguard/ClockEventControllerTest.kt",
-        "tests/src/**/systemui/bluetooth/qsdialog/BluetoothAutoOnRepositoryTest.kt",
+        "tests/src/**/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt",
         "tests/src/**/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt",
         "tests/src/**/systemui/bluetooth/qsdialog/BluetoothTileDialogRepositoryTest.kt",
         "tests/src/**/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt",
+        "tests/src/**/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt",
         "tests/src/**/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt",
         "tests/src/**/systemui/broadcast/UserBroadcastDispatcherTest.kt",
         "tests/src/**/systemui/charging/WiredChargingRippleControllerTest.kt",
         "tests/src/**/systemui/clipboardoverlay/ClipboardModelTest.kt",
         "tests/src/**/systemui/controls/controller/AuxiliaryPersistenceWrapperTest.kt",
-        "tests/src/**/systemui/controls/controller/ControlsBindingControllerImplTest.kt",
         "tests/src/**/systemui/controls/controller/ControlsControllerImplTest.kt",
         "tests/src/**/systemui/controls/controller/DeletionJobServiceTest.kt",
-        "tests/src/**/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt",
+        "tests/src/**/systemui/controls/management/ControlsFavoritingActivityTest.kt",
         "tests/src/**/systemui/controls/ui/ControlsUiControllerImplTest.kt",
-        "tests/src/**/systemui/controls/ui/ControlViewHolderTest.kt",
         "tests/src/**/systemui/controls/ui/SelectionItemTest.kt",
         "tests/src/**/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt",
         "tests/src/**/systemui/media/controls/domain/pipeline/LegacyMediaDataFilterImplTest.kt",
-        "tests/src/**/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt",
+        "tests/src/**/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt",
+        "tests/src/**/systemui/media/controls/ui/MediaPlayerDataTest.kt",
         "tests/src/**/systemui/media/controls/ui/animation/AnimationBindHandlerTest.kt",
         "tests/src/**/systemui/media/controls/ui/animation/ColorSchemeTransitionTest.kt",
         "tests/src/**/systemui/media/controls/ui/animation/MetadataAnimationHandlerTest.kt",
@@ -377,7 +335,6 @@
         "tests/src/**/systemui/media/controls/ui/controller/MediaControlPanelTest.kt",
         "tests/src/**/systemui/media/controls/ui/controller/MediaViewControllerTest.kt",
         "tests/src/**/systemui/media/controls/ui/drawable/SquigglyProgressTest.kt",
-        "tests/src/**/systemui/media/controls/ui/MediaPlayerDataTest.kt",
         "tests/src/**/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt",
         "tests/src/**/systemui/navigationbar/gestural/BackPanelControllerTest.kt",
         "tests/src/**/systemui/notetask/NoteTaskControllerTest.kt",
@@ -386,61 +343,61 @@
         "tests/src/**/systemui/qs/external/CustomTileStatePersisterTest.kt",
         "tests/src/**/systemui/qs/external/TileRequestDialogTest.kt",
         "tests/src/**/systemui/qs/external/TileServiceRequestControllerTest.kt",
-        "tests/src/**/systemui/qs/tileimpl/TilesStatesTextTest.kt",
+        "tests/src/**/systemui/qs/tileimpl/QSTileViewImplTest.kt",
         "tests/src/**/systemui/qs/tiles/AlarmTileTest.kt",
         "tests/src/**/systemui/qs/tiles/BluetoothTileTest.kt",
-        "tests/src/**/systemui/screenshot/ScreenshotPolicyImplTest.kt",
-        "tests/src/**/systemui/settings/DisplayTrackerImplTest.kt",
+        "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt",
+        "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt",
+        "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt",
+        "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt",
+        "tests/src/**/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt",
+        "tests/src/**/systemui/statusbar/phone/fragment/MultiSourceMinAlphaControllerTest.kt",
+        "tests/src/**/systemui/statusbar/phone/FoldStateListenerTest.kt",
+        "tests/src/**/systemui/statusbar/notification/stack/ui/view/NotificationStatsLoggerTest.kt",
+        "tests/src/**/systemui/statusbar/notification/row/TextPrecomputerTest.kt",
+        "tests/src/**/systemui/statusbar/notification/row/SingleLineConversationViewBinderTest.kt",
+        "tests/src/**/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt",
+        "tests/src/**/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt",
+        "tests/src/**/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt",
+        "tests/src/**/systemui/statusbar/notification/logging/NotificationMemoryLoggerTest.kt",
+        "tests/src/**/systemui/statusbar/notification/logging/NotificationMemoryMeterTest.kt",
+        "tests/src/**/systemui/statusbar/notification/logging/NotificationMemoryViewWalkerTest.kt",
+        "tests/src/**/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt",
+        "tests/src/**/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt",
+        "tests/src/**/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt",
+        "tests/src/**/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt",
+        "tests/src/**/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt",
+        "tests/src/**/systemui/statusbar/notification/RoundableTest.kt",
+        "tests/src/**/systemui/stylus/StylusUsiPowerUiTest.kt",
+        "tests/src/**/systemui/statusbar/gesture/GenericGestureDetectorTest.kt",
+        "tests/src/**/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt",
+        "tests/src/**/systemui/statusbar/connectivity/MobileStateTest.kt",
+        "tests/src/**/systemui/statusbar/commandline/CommandParserTest.kt",
+        "tests/src/**/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt",
+        "tests/src/**/systemui/statusbar/LightRevealScrimTest.kt",
+        "tests/src/**/systemui/shade/transition/LargeScreenShadeInterpolatorImplTest.kt",
+        "tests/src/**/systemui/shade/ShadeExpansionStateManagerTest.kt",
+        "tests/src/**/systemui/shade/ShadeHeaderControllerTest.kt",
+        "tests/src/**/systemui/shade/NotificationsQSContainerControllerTest.kt",
         "tests/src/**/systemui/settings/UserFileManagerImplTest.kt",
         "tests/src/**/systemui/settings/UserTrackerImplReceiveTest.kt",
         "tests/src/**/systemui/settings/UserTrackerImplTest.kt",
         "tests/src/**/systemui/shade/GlanceableHubContainerControllerTest.kt",
         "tests/src/**/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt",
-        "tests/src/**/systemui/shade/NotificationsQSContainerControllerTest.kt",
-        "tests/src/**/systemui/shade/ShadeExpansionStateManagerTest.kt",
-        "tests/src/**/systemui/shade/ShadeHeaderControllerTest.kt",
-        "tests/src/**/systemui/shade/transition/LargeScreenShadeInterpolatorImplTest.kt",
-        "tests/src/**/systemui/statusbar/commandline/CommandParserTest.kt",
-        "tests/src/**/systemui/statusbar/connectivity/MobileStateTest.kt",
-        "tests/src/**/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt",
-        "tests/src/**/systemui/statusbar/gesture/GenericGestureDetectorTest.kt",
-        "tests/src/**/systemui/statusbar/LightRevealScrimTest.kt",
-        "tests/src/**/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt",
-        "tests/src/**/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt",
-        "tests/src/**/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt",
-        "tests/src/**/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt",
-        "tests/src/**/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt",
-        "tests/src/**/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt",
-        "tests/src/**/systemui/statusbar/notification/logging/NotificationMemoryLoggerTest.kt",
-        "tests/src/**/systemui/statusbar/notification/logging/NotificationMemoryMeterTest.kt",
-        "tests/src/**/systemui/statusbar/notification/logging/NotificationMemoryViewWalkerTest.kt",
-        "tests/src/**/systemui/statusbar/notification/RoundableTest.kt",
-        "tests/src/**/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt",
-        "tests/src/**/systemui/statusbar/notification/row/SingleLineConversationViewBinderTest.kt",
-        "tests/src/**/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt",
-        "tests/src/**/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt",
-        "tests/src/**/systemui/statusbar/notification/row/TextPrecomputerTest.kt",
-        "tests/src/**/systemui/statusbar/phone/FoldStateListenerTest.kt",
-        "tests/src/**/systemui/statusbar/phone/fragment/MultiSourceMinAlphaControllerTest.kt",
-        "tests/src/**/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt",
-        "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt",
-        "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt",
-        "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt",
-        "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt",
-        "tests/src/**/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt",
-        "tests/src/**/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt",
-        "tests/src/**/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt",
-        "tests/src/**/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt",
-        "tests/src/**/systemui/statusbar/policy/VariableDateViewControllerTest.kt",
-        "tests/src/**/systemui/statusbar/policy/WalletControllerImplTest.kt",
-        "tests/src/**/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt",
-        "tests/src/**/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt",
-        "tests/src/**/systemui/statusbar/policy/BatteryControllerStartableTest.java",
-        "tests/src/**/systemui/shared/plugins/PluginActionManagerTest.java",
-        "tests/src/**/systemui/statusbar/policy/SecurityControllerTest.java",
-        "tests/src/**/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt",
+        "tests/src/**/systemui/screenshot/ScreenshotPolicyImplTest.kt",
+        "tests/src/**/systemui/qs/tileimpl/TilesStatesTextTest.kt",
+        "tests/src/**/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt",
+        "tests/src/**/systemui/controls/ui/ControlViewHolderTest.kt",
+        "tests/src/**/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt",
+        "tests/src/**/systemui/controls/controller/ControlsBindingControllerImplTest.kt",
+        "tests/src/**/systemui/bluetooth/qsdialog/BluetoothAutoOnRepositoryTest.kt",
+        "tests/src/**/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt",
+        "tests/src/**/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt",
+        "tests/src/**/systemui/controls/management/ControlsProviderSelectorActivityTest.kt",
+        "tests/src/**/systemui/settings/DisplayTrackerImplTest.kt",
+        "tests/src/**/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt",
+        "tests/src/**/systemui/wmshell/BubblesTest.java",
     ],
-    visibility: ["//visibility:private"],
 }
 
 //Create a library to expose SystemUI's resources to other modules.
@@ -903,9 +860,8 @@
     ],
     exclude_srcs: [
         ":SystemUI-tests-broken-robofiles-mockito-extended",
-        ":SystemUI-tests-broken-robofiles-compile",
+        ":SystemUI-tests-broken-robofiles-internal",
         ":SystemUI-tests-broken-robofiles-run",
-        ":SystemUI-tests-broken-robofiles-sysui-run",
     ],
     static_libs: [
         "RoboTestLibraries",
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index e47704eb..cc01071 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -55,14 +55,6 @@
           "exclude-filter": "android.platform.tests.HomeTest#testAssistantWidget"
         }
       ]
-    },
-    {
-      "name": "AndroidAutomotiveNotificationsTests",
-      "options" : [
-        {
-          "include-filter": "android.platform.tests.NotificationTest"
-        }
-      ]
     }
   ],
 
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/activity/A11yMenuSettingsActivity.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/activity/A11yMenuSettingsActivity.java
index c71ef83..129dd9b 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/activity/A11yMenuSettingsActivity.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/activity/A11yMenuSettingsActivity.java
@@ -36,7 +36,6 @@
 import androidx.preference.PreferenceFragmentCompat;
 import androidx.preference.PreferenceManager;
 
-import com.android.systemui.accessibility.accessibilitymenu.Flags;
 import com.android.systemui.accessibility.accessibilitymenu.R;
 
 /**
@@ -62,10 +61,8 @@
         ((TextView) findViewById(R.id.action_bar_title)).setText(
                 getResources().getString(R.string.accessibility_menu_settings_name)
         );
-        if (Flags.actionBarWrapContent()) {
-            setHeightWrapContent(findViewById(com.android.internal.R.id.action_bar));
-            setHeightWrapContent(findViewById(com.android.internal.R.id.action_bar_container));
-        }
+        setHeightWrapContent(findViewById(com.android.internal.R.id.action_bar));
+        setHeightWrapContent(findViewById(com.android.internal.R.id.action_bar_container));
     }
 
     private void setHeightWrapContent(View view) {
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
index 3db61a5..6bc0f42 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
@@ -220,9 +220,6 @@
 
     @SuppressLint("MissingPermission")
     private boolean isShortcutRestricted(int shortcutId) {
-        if (!Flags.hideRestrictedActions()) {
-            return false;
-        }
         final UserManager userManager = mService.getSystemService(UserManager.class);
         if (userManager == null) {
             return false;
@@ -366,12 +363,11 @@
         if (mLayout.getVisibility() == View.VISIBLE) {
             mLayout.setVisibility(View.GONE);
         } else {
-            if (Flags.hideRestrictedActions()) {
-                // Reconfigure the shortcut list in case the set of restricted actions has changed.
-                mA11yMenuViewPager.configureViewPagerAndFooter(
-                        mLayout, createShortcutList(), getPageIndex());
-                updateViewLayout();
-            }
+            // Reconfigure the shortcut list in case the set of restricted actions has changed.
+            mA11yMenuViewPager.configureViewPagerAndFooter(
+                    mLayout, createShortcutList(), getPageIndex());
+            updateViewLayout();
+
             mLayout.setVisibility(View.VISIBLE);
         }
     }
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 4ab771b..7172619 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
@@ -46,9 +46,6 @@
 import android.media.AudioManager;
 import android.os.PowerManager;
 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.uiautomator_helpers.WaitUtils;
 import android.provider.Settings;
 import android.util.Log;
@@ -63,7 +60,6 @@
 import androidx.test.uiautomator.UiDevice;
 
 import com.android.compatibility.common.util.TestUtils;
-import com.android.systemui.accessibility.accessibilitymenu.Flags;
 import com.android.systemui.accessibility.accessibilitymenu.model.A11yMenuShortcut.ShortcutId;
 
 import org.junit.After;
@@ -71,7 +67,6 @@
 import org.junit.Assume;
 import org.junit.Before;
 import org.junit.BeforeClass;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -82,9 +77,6 @@
 
 @RunWith(AndroidJUnit4.class)
 public class AccessibilityMenuServiceTest {
-    @Rule
-    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-
     private static final String TAG = "A11yMenuServiceTest";
     private static final int CLICK_ID = AccessibilityNodeInfo.ACTION_CLICK;
 
@@ -499,7 +491,6 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_HIDE_RESTRICTED_ACTIONS)
     public void testRestrictedActions_BrightnessNotAvailable() throws Throwable {
         try {
             setUserRestriction(UserManager.DISALLOW_CONFIG_BRIGHTNESS, true);
@@ -519,7 +510,6 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_HIDE_RESTRICTED_ACTIONS)
     public void testRestrictedActions_VolumeNotAvailable() throws Throwable {
         try {
             setUserRestriction(UserManager.DISALLOW_ADJUST_VOLUME, true);
diff --git a/packages/SystemUI/aconfig/biometrics_framework.aconfig b/packages/SystemUI/aconfig/biometrics_framework.aconfig
index 10d7352..e3f5378 100644
--- a/packages/SystemUI/aconfig/biometrics_framework.aconfig
+++ b/packages/SystemUI/aconfig/biometrics_framework.aconfig
@@ -12,3 +12,10 @@
     purpose: PURPOSE_BUGFIX
   }
 }
+
+flag {
+    name: "cont_auth_plugin"
+    namespace: "biometrics_framework"
+    description: "Plugin and related API hooks for contextual auth plugins"
+    bug: "373600589"
+}
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 3541742..0d654d9 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1201,6 +1201,16 @@
 }
 
 flag {
+  name: "communal_hub_use_thread_pool_for_widgets"
+  namespace: "systemui"
+  description: "Use a dedicated thread pool executor for loading widgets on glanceable hub"
+  bug: "369412569"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
   name: "communal_standalone_support"
   namespace: "systemui"
   description: "Support communal features without a dock"
@@ -1215,6 +1225,13 @@
 }
 
 flag {
+  name: "glanceable_hub_v2"
+  namespace: "systemui"
+  description: "Gates the refreshed glanceable hub experience that also brings the glanceable hub to mobile phones"
+  bug: "375689917"
+}
+
+flag {
     name: "dream_overlay_updated_font"
     namespace: "systemui"
     description: "Flag to enable updated font settings for dream overlay"
@@ -1502,6 +1519,16 @@
 }
 
 flag {
+   name: "sim_pin_use_slot_id"
+   namespace: "systemui"
+   description: "Reorient SIM data processing around slotId instead of subId"
+   bug: "376173142"
+   metadata {
+        purpose: PURPOSE_BUGFIX
+   }
+}
+
+flag {
    name: "use_transitions_for_keyguard_occluded"
    namespace: "systemui"
    description: "Use Keyguard Transitions to set Notification Shade occlusion state"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
index eee0caf..38f0998 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.animation
 
 import android.app.ActivityManager
+import android.app.ActivityOptions
 import android.app.ActivityTaskManager
 import android.app.PendingIntent
 import android.app.TaskInfo
@@ -434,8 +435,7 @@
                     private fun cleanUp() {
                         cleanUpRunnable?.run()
                     }
-                },
-                initializeLazily = longLivedReturnAnimationsEnabled(),
+                }
             )
 
         // mTypeSet and mModes match back signals only, and not home. This is on purpose, because
@@ -478,8 +478,8 @@
     /** Create a new animation [Runner] controlled by [controller]. */
     @VisibleForTesting
     @JvmOverloads
-    fun createRunner(controller: Controller, initializeLazily: Boolean = false): Runner {
-        if (initializeLazily) assertLongLivedReturnAnimations()
+    fun createRunner(controller: Controller, longLived: Boolean = false): Runner {
+        if (longLived) assertLongLivedReturnAnimations()
 
         // Make sure we use the modified timings when animating a dialog into an app.
         val transitionAnimator =
@@ -489,13 +489,7 @@
                 transitionAnimator
             }
 
-        return Runner(
-            controller,
-            callback!!,
-            transitionAnimator,
-            lifecycleListener,
-            initializeLazily,
-        )
+        return Runner(controller, callback!!, transitionAnimator, lifecycleListener, longLived)
     }
 
     interface PendingIntentStarter {
@@ -699,7 +693,7 @@
             }
         val launchRemoteTransition =
             RemoteTransition(
-                OriginTransition(createRunner(controller, initializeLazily = true)),
+                OriginTransition(createRunner(controller, longLived = true)),
                 "${cookie}_launchTransition",
             )
         transitionRegister.register(launchFilter, launchRemoteTransition, includeTakeover = true)
@@ -708,6 +702,8 @@
             object : Controller by controller {
                 override val isLaunching: Boolean = false
             }
+        // Cross-task close transitions should not use this animation, so we only register it for
+        // when the opening window is Launcher.
         val returnFilter =
             TransitionFilter().apply {
                 mRequirements =
@@ -716,12 +712,16 @@
                             mActivityType = WindowConfiguration.ACTIVITY_TYPE_STANDARD
                             mModes = intArrayOf(TRANSIT_CLOSE, TRANSIT_TO_BACK)
                             mTopActivity = component
-                        }
+                        },
+                        TransitionFilter.Requirement().apply {
+                            mActivityType = WindowConfiguration.ACTIVITY_TYPE_HOME
+                            mModes = intArrayOf(TRANSIT_OPEN, TRANSIT_TO_FRONT)
+                        },
                     )
             }
         val returnRemoteTransition =
             RemoteTransition(
-                OriginTransition(createRunner(returnController, initializeLazily = true)),
+                OriginTransition(createRunner(returnController, longLived = true)),
                 "${cookie}_returnTransition",
             )
         transitionRegister.register(returnFilter, returnRemoteTransition, includeTakeover = true)
@@ -910,14 +910,22 @@
 
     @VisibleForTesting
     inner class Runner(
-        private val controller: Controller,
+        /**
+         * This can hold a reference to a view, so it needs to be cleaned up and can't be held on to
+         * forever when ![longLived].
+         */
+        private var controller: Controller?,
         private val callback: Callback,
         /** The animator to use to animate the window transition. */
         private val transitionAnimator: TransitionAnimator,
         /** Listener for animation lifecycle events. */
         private val listener: Listener? = null,
-        /** Whether the internal [delegate] should be initialized lazily. */
-        private val initializeLazily: Boolean = false,
+        /**
+         * Whether the internal should be kept around after execution for later usage. IMPORTANT:
+         * should always be false if this [Runner] is to be used directly with [ActivityOptions]
+         * (i.e. for ephemeral launches), or the controller will leak its view.
+         */
+        private val longLived: Boolean = false,
     ) : IRemoteAnimationRunner.Stub() {
         // This is being passed across IPC boundaries and cycles (through PendingIntentRecords,
         // etc.) are possible. So we need to make sure we drop any references that might
@@ -926,7 +934,7 @@
 
         init {
             delegate = null
-            if (!initializeLazily) {
+            if (!longLived) {
                 // Ephemeral launches bundle the runner with the launch request (instead of being
                 // registered ahead of time for later use). This means that there could be a timeout
                 // between creation and invocation, so the delegate needs to exist from the
@@ -1004,16 +1012,17 @@
 
         @AnyThread
         private fun maybeSetUp() {
-            if (!initializeLazily || delegate != null) return
+            if (!longLived || delegate != null) return
             createDelegate()
         }
 
         @AnyThread
         private fun createDelegate() {
+            if (controller == null) return
             delegate =
                 AnimationDelegate(
                     mainExecutor,
-                    controller,
+                    controller!!,
                     callback,
                     DelegatingAnimationCompletionListener(listener, this::dispose),
                     transitionAnimator,
@@ -1025,7 +1034,12 @@
         fun dispose() {
             // Drop references to animation controller once we're done with the animation
             // to avoid leaking.
-            mainExecutor.execute { delegate = null }
+            mainExecutor.execute {
+                delegate = null
+                // When long lived, the same Runner can be used more than once. In this case we need
+                // to keep the controller around so we can rebuild the delegate on demand.
+                if (!longLived) controller = null
+            }
         }
     }
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
index ae92d259..85f549d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
@@ -21,6 +21,7 @@
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
 import androidx.compose.ui.Modifier
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.SceneScope
@@ -71,9 +72,7 @@
     }
 
     @Composable
-    override fun SceneScope.Content(
-        modifier: Modifier,
-    ) =
+    override fun SceneScope.Content(modifier: Modifier) =
         BouncerScene(
             viewModel = rememberViewModel("BouncerScene") { contentViewModelFactory.create() },
             dialogFactory = dialogFactory,
@@ -89,6 +88,8 @@
 ) {
     val backgroundColor = MaterialTheme.colorScheme.surface
 
+    DisposableEffect(Unit) { onDispose { viewModel.onUiDestroyed() } }
+
     Box(modifier) {
         Canvas(Modifier.element(Bouncer.Elements.Background).fillMaxSize()) {
             drawRect(color = backgroundColor)
@@ -101,7 +102,7 @@
             dialogFactory,
             Modifier.element(Bouncer.Elements.Content)
                 .sysuiResTag(Bouncer.TestTags.Root)
-                .fillMaxSize()
+                .fillMaxSize(),
         )
     }
 }
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 87e9c42..4705d8d 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
@@ -44,6 +44,7 @@
 import com.android.compose.animation.scene.Swipe
 import com.android.compose.animation.scene.observableTransitionState
 import com.android.compose.animation.scene.transitions
+import com.android.systemui.Flags.communalHubOnMobile
 import com.android.systemui.communal.shared.model.CommunalBackgroundType
 import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.communal.shared.model.CommunalTransitionKeys
@@ -186,15 +187,19 @@
     ) {
         scene(
             CommunalScenes.Blank,
-            userActions = mapOf(Swipe.Start(fromSource = Edge.End) to CommunalScenes.Communal),
+            userActions =
+                if (communalHubOnMobile()) emptyMap()
+                else mapOf(Swipe.Start(fromSource = Edge.End) to CommunalScenes.Communal),
         ) {
             // This scene shows nothing only allowing for transitions to the communal scene.
             Box(modifier = Modifier.fillMaxSize())
         }
 
-        val userActions = mapOf(Swipe.End to CommunalScenes.Blank)
-
-        scene(CommunalScenes.Communal, userActions = userActions) {
+        scene(
+            CommunalScenes.Communal,
+            userActions =
+                if (communalHubOnMobile()) emptyMap() else mapOf(Swipe.End to CommunalScenes.Blank),
+        ) {
             CommunalScene(
                 backgroundType = backgroundType,
                 colors = colors,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 5b1203f..787edfb 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -141,6 +141,7 @@
 import androidx.compose.ui.semantics.clearAndSetSemantics
 import androidx.compose.ui.semantics.contentDescription
 import androidx.compose.ui.semantics.customActions
+import androidx.compose.ui.semantics.heading
 import androidx.compose.ui.semantics.onClick
 import androidx.compose.ui.semantics.paneTitle
 import androidx.compose.ui.semantics.semantics
@@ -902,11 +903,17 @@
                 Arrangement.spacedBy(Dimensions.Spacing, Alignment.CenterVertically),
             horizontalAlignment = Alignment.CenterHorizontally,
         ) {
+            val titleForEmptyStateCTA = stringResource(R.string.title_for_empty_state_cta)
             Text(
-                text = stringResource(R.string.title_for_empty_state_cta),
+                text = titleForEmptyStateCTA,
                 style = MaterialTheme.typography.displaySmall,
                 textAlign = TextAlign.Center,
                 color = colors.secondary,
+                modifier =
+                    Modifier.focusable().semantics(mergeDescendants = true) {
+                        contentDescription = titleForEmptyStateCTA
+                        heading()
+                    },
             )
             Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
                 Button(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalTouchableSurface.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalTouchableSurface.kt
index 3707a87..f2edec6 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalTouchableSurface.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalTouchableSurface.kt
@@ -27,6 +27,8 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.input.key.onPreviewKeyEvent
 import androidx.compose.ui.input.pointer.motionEventSpy
+import androidx.compose.ui.semantics.hideFromAccessibility
+import androidx.compose.ui.semantics.semantics
 import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
 
 @OptIn(ExperimentalFoundationApi::class, ExperimentalComposeUiApi::class)
@@ -42,6 +44,9 @@
     Box(
         modifier =
             modifier
+                // The touchable surface is hidden for accessibility because these actions are
+                // already provided through custom accessibility actions.
+                .semantics { hideFromAccessibility() }
                 .combinedClickable(
                     onLongClick = viewModel::onLongClick,
                     onClick = viewModel::onClick,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
index ef5e90b..7a50080 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
@@ -94,7 +94,7 @@
     private val scope: CoroutineScope,
     private val updateDragPositionForRemove: (draggingBoundingBox: IntRect) -> Boolean,
 ) {
-    var draggingItemKey by mutableStateOf<Any?>(null)
+    var draggingItemKey by mutableStateOf<String?>(null)
         private set
 
     var isDraggingToRemove by mutableStateOf(false)
@@ -138,7 +138,7 @@
             // before content padding from the initial pointer position
             .firstItemAtOffset(normalizedOffset - contentOffset)
             ?.apply {
-                draggingItemKey = key
+                draggingItemKey = key as String
                 draggingItemInitialOffset = this.offset.toOffset()
                 return true
             }
@@ -284,7 +284,9 @@
                             contentOffset,
                         )
                     ) {
-                        viewModel.onReorderWidgetStart()
+                        // draggingItemKey is guaranteed to be non-null here because it is set in
+                        // onDragStart()
+                        viewModel.onReorderWidgetStart(dragDropState.draggingItemKey!!)
                     }
                 },
                 onDragEnd = {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResponsiveLazyHorizontalGrid.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResponsiveLazyHorizontalGrid.kt
new file mode 100644
index 0000000..e331078
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResponsiveLazyHorizontalGrid.kt
@@ -0,0 +1,234 @@
+/*
+ * 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.ui.compose
+
+import android.content.res.Configuration
+import androidx.compose.foundation.OverscrollEffect
+import androidx.compose.foundation.gestures.FlingBehavior
+import androidx.compose.foundation.gestures.ScrollableDefaults
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.BoxWithConstraints
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.calculateEndPadding
+import androidx.compose.foundation.layout.calculateStartPadding
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.lazy.grid.GridCells
+import androidx.compose.foundation.lazy.grid.LazyGridScope
+import androidx.compose.foundation.lazy.grid.LazyGridState
+import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
+import androidx.compose.foundation.lazy.grid.rememberLazyGridState
+import androidx.compose.foundation.rememberOverscrollEffect
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.DpSize
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.coerceAtMost
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.times
+
+/**
+ * Renders a responsive [LazyHorizontalGrid] with dynamic columns and rows. Each cell will maintain
+ * the specified aspect ratio, but is otherwise resizeable in order to best fill the available
+ * space.
+ */
+@Composable
+fun ResponsiveLazyHorizontalGrid(
+    cellAspectRatio: Float,
+    modifier: Modifier = Modifier,
+    state: LazyGridState = rememberLazyGridState(),
+    minContentPadding: PaddingValues = PaddingValues(0.dp),
+    minHorizontalArrangement: Dp = 0.dp,
+    minVerticalArrangement: Dp = 0.dp,
+    flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(),
+    userScrollEnabled: Boolean = true,
+    overscrollEffect: OverscrollEffect? = rememberOverscrollEffect(),
+    content: LazyGridScope.(sizeInfo: SizeInfo) -> Unit,
+) {
+    check(cellAspectRatio > 0f) { "Aspect ratio must be greater than 0, but was $cellAspectRatio" }
+    check(minHorizontalArrangement.value >= 0f && minVerticalArrangement.value >= 0f) {
+        "Horizontal and vertical arrangements must be non-negative, but were " +
+            "$minHorizontalArrangement and $minVerticalArrangement, respectively."
+    }
+    BoxWithConstraints(modifier) {
+        val gridSize = rememberGridSize(maxWidth = maxWidth, maxHeight = maxHeight)
+        val layoutDirection = LocalLayoutDirection.current
+
+        val minStartPadding = minContentPadding.calculateStartPadding(layoutDirection)
+        val minEndPadding = minContentPadding.calculateEndPadding(layoutDirection)
+        val minTopPadding = minContentPadding.calculateTopPadding()
+        val minBottomPadding = minContentPadding.calculateBottomPadding()
+        val minHorizontalPadding = minStartPadding + minEndPadding
+        val minVerticalPadding = minTopPadding + minBottomPadding
+
+        // Determine the maximum allowed cell width and height based on the available width and
+        // height, and the desired number of columns and rows.
+        val maxCellWidth =
+            calculateCellSize(
+                availableSpace = maxWidth,
+                padding = minHorizontalPadding,
+                numCells = gridSize.width,
+                cellSpacing = minHorizontalArrangement,
+            )
+        val maxCellHeight =
+            calculateCellSize(
+                availableSpace = maxHeight,
+                padding = minVerticalPadding,
+                numCells = gridSize.height,
+                cellSpacing = minVerticalArrangement,
+            )
+
+        // Constrain the max size to the desired aspect ratio.
+        val finalSize =
+            calculateClosestSize(
+                maxWidth = maxCellWidth,
+                maxHeight = maxCellHeight,
+                aspectRatio = cellAspectRatio,
+            )
+
+        // Determine how much space in each dimension we've used up, and how much we have left as
+        // extra space. Distribute the extra space evenly along the content padding.
+        val usedWidth =
+            calculateUsedSpace(
+                    cellSize = finalSize.width,
+                    numCells = gridSize.width,
+                    padding = minHorizontalPadding,
+                    cellSpacing = minHorizontalArrangement,
+                )
+                .coerceAtMost(maxWidth)
+        val usedHeight =
+            calculateUsedSpace(
+                    cellSize = finalSize.height,
+                    numCells = gridSize.height,
+                    padding = minVerticalPadding,
+                    cellSpacing = minVerticalArrangement,
+                )
+                .coerceAtMost(maxHeight)
+        val extraWidth = maxWidth - usedWidth
+        val extraHeight = maxHeight - usedHeight
+
+        val finalContentPadding =
+            PaddingValues(
+                start = minStartPadding + extraWidth / 2,
+                end = minEndPadding + extraWidth / 2,
+                top = minTopPadding + extraHeight / 2,
+                bottom = minBottomPadding + extraHeight / 2,
+            )
+
+        LazyHorizontalGrid(
+            rows = GridCells.Fixed(gridSize.height),
+            modifier = Modifier.fillMaxSize(),
+            state = state,
+            contentPadding = finalContentPadding,
+            horizontalArrangement = Arrangement.spacedBy(minHorizontalArrangement),
+            verticalArrangement = Arrangement.spacedBy(minVerticalArrangement),
+            flingBehavior = flingBehavior,
+            userScrollEnabled = userScrollEnabled,
+            overscrollEffect = overscrollEffect,
+        ) {
+            content(
+                SizeInfo(
+                    cellSize = finalSize,
+                    contentPadding = finalContentPadding,
+                    horizontalArrangement = minHorizontalArrangement,
+                    verticalArrangement = minVerticalArrangement,
+                    maxHeight = maxHeight,
+                )
+            )
+        }
+    }
+}
+
+private fun calculateCellSize(availableSpace: Dp, padding: Dp, numCells: Int, cellSpacing: Dp): Dp =
+    (availableSpace - padding - cellSpacing * (numCells - 1)) / numCells
+
+private fun calculateUsedSpace(cellSize: Dp, numCells: Int, padding: Dp, cellSpacing: Dp): Dp =
+    cellSize * numCells + padding + (numCells - 1) * cellSpacing
+
+private fun calculateClosestSize(maxWidth: Dp, maxHeight: Dp, aspectRatio: Float): DpSize {
+    return if (maxWidth / maxHeight > aspectRatio) {
+        // Target is too wide, shrink width
+        DpSize(maxHeight * aspectRatio, maxHeight)
+    } else {
+        // Target is too tall, shrink height
+        DpSize(maxWidth, maxWidth / aspectRatio)
+    }
+}
+
+/**
+ * Provides size info of the responsive grid, since the size is dynamic.
+ *
+ * @property cellSize The size of each cell in the grid.
+ * @property contentPadding The final content padding of the grid.
+ * @property horizontalArrangement The space between columns in the grid.
+ * @property verticalArrangement The space between rows in the grid.
+ * @property availableHeight The maximum height an item in the grid may occupy.
+ */
+data class SizeInfo(
+    val cellSize: DpSize,
+    val contentPadding: PaddingValues,
+    val horizontalArrangement: Dp,
+    val verticalArrangement: Dp,
+    private val maxHeight: Dp,
+) {
+    val availableHeight: Dp
+        get() =
+            maxHeight -
+                contentPadding.calculateBottomPadding() -
+                contentPadding.calculateTopPadding()
+}
+
+@Composable
+private fun rememberGridSize(maxWidth: Dp, maxHeight: Dp): IntSize {
+    val configuration = LocalConfiguration.current
+    val orientation = configuration.orientation
+
+    return remember(orientation, maxWidth, maxHeight) {
+        if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+            IntSize(
+                width = calculateNumCellsWidth(maxWidth),
+                height = calculateNumCellsHeight(maxHeight),
+            )
+        } else {
+            // In landscape we invert the rows/columns to ensure we match the same area as portrait.
+            // This keeps the number of elements in the grid consistent when changing orientation.
+            IntSize(
+                width = calculateNumCellsHeight(maxWidth),
+                height = calculateNumCellsWidth(maxHeight),
+            )
+        }
+    }
+}
+
+private fun calculateNumCellsWidth(width: Dp) =
+    // See https://developer.android.com/develop/ui/views/layout/use-window-size-classes
+    when {
+        width >= 840.dp -> 3
+        width >= 600.dp -> 2
+        else -> 1
+    }
+
+private fun calculateNumCellsHeight(height: Dp) =
+    // See https://developer.android.com/develop/ui/views/layout/use-window-size-classes
+    when {
+        height >= 900.dp -> 3
+        height >= 480.dp -> 2
+        else -> 1
+    }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
index 2a2c2fc..105e8da 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
@@ -21,7 +21,6 @@
 import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
@@ -70,10 +69,7 @@
     override val id: String = "default"
 
     @Composable
-    override fun SceneScope.Content(
-        viewModel: LockscreenContentViewModel,
-        modifier: Modifier,
-    ) {
+    override fun SceneScope.Content(viewModel: LockscreenContentViewModel, modifier: Modifier) {
         val isUdfpsVisible = viewModel.isUdfpsVisible
         val isShadeLayoutWide by viewModel.isShadeLayoutWide.collectAsStateWithLifecycle()
         val unfoldTranslations by viewModel.unfoldTranslations.collectAsStateWithLifecycle()
@@ -85,22 +81,18 @@
             with(notificationSection) { HeadsUpNotifications() }
         }
 
-        LockscreenLongPress(
-            viewModel = viewModel.touchHandling,
-            modifier = modifier,
-        ) { onSettingsMenuPlaced ->
+        LockscreenLongPress(viewModel = viewModel.touchHandling, modifier = modifier) {
+            onSettingsMenuPlaced ->
             Layout(
                 content = {
                     // Constrained to above the lock icon.
-                    Column(
-                        modifier = Modifier.fillMaxSize(),
-                    ) {
+                    Column(modifier = Modifier.fillMaxSize()) {
                         with(statusBarSection) {
                             StatusBar(
                                 modifier =
                                     Modifier.fillMaxWidth()
                                         .padding(
-                                            horizontal = { unfoldTranslations.start.roundToInt() },
+                                            horizontal = { unfoldTranslations.start.roundToInt() }
                                         )
                             )
                         }
@@ -109,13 +101,14 @@
                             with(topAreaSection) {
                                 DefaultClockLayout(
                                     smartSpacePaddingTop = viewModel::getSmartSpacePaddingTop,
+                                    isShadeLayoutWide = isShadeLayoutWide,
                                     modifier =
                                         Modifier.thenIf(isShadeLayoutWide) {
                                                 Modifier.fillMaxWidth(0.5f)
                                             }
                                             .graphicsLayer {
                                                 translationX = unfoldTranslations.start
-                                            }
+                                            },
                                 )
                             }
                             if (isShadeLayoutWide && !isBypassEnabled) {
@@ -127,7 +120,7 @@
                                         modifier =
                                             Modifier.fillMaxWidth(0.5f)
                                                 .fillMaxHeight()
-                                                .align(alignment = Alignment.TopEnd)
+                                                .align(alignment = Alignment.TopEnd),
                                     )
                                 }
                             }
@@ -142,7 +135,7 @@
                                     AodNotificationIcons(
                                         modifier =
                                             Modifier.align(alignment = Alignment.TopStart)
-                                                .padding(start = aodIconPadding),
+                                                .padding(start = aodIconPadding)
                                     )
                                     Notifications(
                                         areNotificationsVisible = areNotificationsVisible,
@@ -152,7 +145,7 @@
                                 }
                             } else {
                                 AodNotificationIcons(
-                                    modifier = Modifier.padding(start = aodIconPadding),
+                                    modifier = Modifier.padding(start = aodIconPadding)
                                 )
                             }
                         }
@@ -205,11 +198,7 @@
                 val endShortcutMeasurable = measurables[4]
                 val settingsMenuMeasurable = measurables[5]
 
-                val noMinConstraints =
-                    constraints.copy(
-                        minWidth = 0,
-                        minHeight = 0,
-                    )
+                val noMinConstraints = constraints.copy(minWidth = 0, minHeight = 0)
                 val lockIconPlaceable = lockIconMeasurable.measure(noMinConstraints)
                 val lockIconBounds =
                     IntRect(
@@ -235,14 +224,8 @@
                 val settingsMenuPlaceable = settingsMenuMeasurable.measure(noMinConstraints)
 
                 layout(constraints.maxWidth, constraints.maxHeight) {
-                    aboveLockIconPlaceable.place(
-                        x = 0,
-                        y = 0,
-                    )
-                    lockIconPlaceable.place(
-                        x = lockIconBounds.left,
-                        y = lockIconBounds.top,
-                    )
+                    aboveLockIconPlaceable.place(x = 0, y = 0)
+                    lockIconPlaceable.place(x = lockIconBounds.left, y = lockIconBounds.top)
                     belowLockIconPlaceable.place(
                         x = 0,
                         y = constraints.maxHeight - belowLockIconPlaceable.height,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
index 3ca2b9c..4a9f44b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
@@ -17,9 +17,11 @@
 package com.android.systemui.keyguard.ui.composable.section
 
 import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.dimensionResource
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.SceneScope
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardMediaViewModel
@@ -27,6 +29,7 @@
 import com.android.systemui.media.controls.ui.controller.MediaCarouselController
 import com.android.systemui.media.controls.ui.view.MediaHost
 import com.android.systemui.media.dagger.MediaModule
+import com.android.systemui.res.R
 import javax.inject.Inject
 import javax.inject.Named
 
@@ -39,13 +42,22 @@
 ) {
 
     @Composable
-    fun SceneScope.KeyguardMediaCarousel() {
+    fun SceneScope.KeyguardMediaCarousel(
+        isShadeLayoutWide: Boolean,
+        modifier: Modifier = Modifier,
+    ) {
         val isMediaVisible by keyguardMediaViewModel.isMediaVisible.collectAsStateWithLifecycle()
-
+        val horizontalPadding =
+            if (isShadeLayoutWide) {
+                dimensionResource(id = R.dimen.notification_side_paddings)
+            } else {
+                dimensionResource(id = R.dimen.notification_side_paddings) +
+                    dimensionResource(id = R.dimen.notification_panel_margin_horizontal)
+            }
         MediaCarousel(
             isVisible = isMediaVisible,
             mediaHost = mediaHost,
-            modifier = Modifier.fillMaxWidth(),
+            modifier = modifier.fillMaxWidth().padding(horizontal = horizontalPadding),
             carouselController = mediaCarouselController,
         )
     }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
index afa92f2..db33e7c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
@@ -63,6 +63,7 @@
     @Composable
     fun SceneScope.DefaultClockLayout(
         smartSpacePaddingTop: (Resources) -> Int,
+        isShadeLayoutWide: Boolean,
         modifier: Modifier = Modifier,
     ) {
         val currentClockLayout by clockViewModel.currentClockLayout.collectAsStateWithLifecycle()
@@ -128,7 +129,7 @@
                     )
                 }
             }
-            with(mediaCarouselSection) { KeyguardMediaCarousel() }
+            with(mediaCarouselSection) { KeyguardMediaCarousel(isShadeLayoutWide) }
         }
     }
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
index e725ce5..58336c2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
@@ -79,8 +79,8 @@
         val MediaLandscapeTopOffset = ValueKey("MediaLandscapeTopOffset")
 
         object MediaOffset {
-            // Brightness + padding
-            val InQS = 92.dp
+            // Brightness
+            val InQS = 60.dp
             val Default = 0.dp
 
             @Composable
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 0e7165c..52adaf2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -74,6 +74,7 @@
 import com.android.compose.animation.scene.animateSceneDpAsState
 import com.android.compose.animation.scene.animateSceneFloatAsState
 import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.modifiers.padding
 import com.android.compose.modifiers.thenIf
 import com.android.compose.windowsizeclass.LocalWindowSizeClass
 import com.android.systemui.battery.BatteryMeterViewController
@@ -379,7 +380,11 @@
                             mediaHost = mediaHost,
                             modifier =
                                 Modifier.fillMaxWidth()
-                                    .layoutId(QSMediaMeasurePolicy.LayoutId.Media),
+                                    .layoutId(QSMediaMeasurePolicy.LayoutId.Media)
+                                    .padding(
+                                        horizontal =
+                                            dimensionResource(id = R.dimen.qs_horizontal_margin)
+                                    ),
                             carouselController = mediaCarouselController,
                         )
                     }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
index 26c827a..3fce890 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
@@ -44,8 +44,11 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.lifecycle.rememberViewModel
 import com.android.systemui.notifications.ui.composable.SnoozeableHeadsUpNotificationSpace
+import com.android.systemui.plugins.qs.TileDetailsViewModel
 import com.android.systemui.qs.composefragment.ui.GridAnchor
+import com.android.systemui.qs.flags.QsDetailedView
 import com.android.systemui.qs.panels.ui.compose.EditMode
+import com.android.systemui.qs.panels.ui.compose.TileDetails
 import com.android.systemui.qs.panels.ui.compose.TileGrid
 import com.android.systemui.qs.ui.viewmodel.QuickSettingsContainerViewModel
 import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeOverlayActionsViewModel
@@ -116,24 +119,50 @@
     }
 }
 
+// A sealed interface to represent the possible states of the `ShadeBody`
+sealed interface ShadeBodyState {
+    data object Editing : ShadeBodyState
+    data object TileDetails : ShadeBodyState
+    data object Default : ShadeBodyState
+}
+
+// Function to map the current state of the `ShadeBody`
+fun checkQsState(isEditing: Boolean, tileDetails: TileDetailsViewModel?): ShadeBodyState {
+    if (isEditing) {
+        return ShadeBodyState.Editing
+    } else if (tileDetails != null && QsDetailedView.isEnabled) {
+        return ShadeBodyState.TileDetails
+    }
+    return ShadeBodyState.Default
+}
+
 @Composable
 fun SceneScope.ShadeBody(viewModel: QuickSettingsContainerViewModel) {
     val isEditing by viewModel.editModeViewModel.isEditing.collectAsStateWithLifecycle()
+    val tileDetails = viewModel.detailsViewModel.activeTileDetails
 
     AnimatedContent(
-        targetState = isEditing,
+        targetState = checkQsState(isEditing, tileDetails),
         transitionSpec = { fadeIn(tween(500)) togetherWith fadeOut(tween(500)) },
-    ) { editing ->
-        if (editing) {
-            EditMode(
-                viewModel = viewModel.editModeViewModel,
-                modifier = Modifier.fillMaxWidth().padding(QuickSettingsShade.Dimensions.Padding),
-            )
-        } else {
-            QuickSettingsLayout(
-                viewModel = viewModel,
-                modifier = Modifier.sysuiResTag("quick_settings_panel"),
-            )
+    ) { state ->
+        when (state) {
+            ShadeBodyState.Editing -> {
+                EditMode(
+                    viewModel = viewModel.editModeViewModel,
+                    modifier = Modifier
+                        .fillMaxWidth()
+                        .padding(QuickSettingsShade.Dimensions.Padding),
+                )
+            }
+            ShadeBodyState.TileDetails -> {
+                TileDetails(viewModel.detailsViewModel)
+            }
+            else -> {
+                QuickSettingsLayout(
+                    viewModel = viewModel,
+                    modifier = Modifier.sysuiResTag("quick_settings_panel"),
+                )
+            }
         }
     }
 }
@@ -168,7 +197,6 @@
                 modifier =
                     Modifier.fillMaxWidth()
                         .heightIn(max = QuickSettingsShade.Dimensions.GridMaxHeight),
-                viewModel.editModeViewModel::startEditing,
             )
         }
     }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
index ae5dd8a..5fb9416 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
@@ -19,12 +19,17 @@
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.animation.scene.UserAction
 import com.android.compose.animation.scene.UserActionResult
 import com.android.compose.animation.scene.animateContentDpAsState
 import com.android.compose.animation.scene.animateContentFloatAsState
+import com.android.compose.animation.scene.content.state.TransitionState
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.lifecycle.ExclusiveActivatable
 import com.android.systemui.lifecycle.rememberViewModel
@@ -63,9 +68,25 @@
     }
 
     @Composable
-    override fun SceneScope.Content(
-        modifier: Modifier,
-    ) {
+    override fun SceneScope.Content(modifier: Modifier) {
+
+        val isIdle by remember {
+            derivedStateOf { layoutState.transitionState is TransitionState.Idle }
+        }
+
+        LaunchedEffect(isIdle) {
+            // Wait for being Idle on this Scene, otherwise LaunchedEffect would fire too soon,
+            // and another transition could override the NSSL stack bounds.
+            if (isIdle) {
+                // Reset the stack bounds to avoid caching these values from the previous Scenes,
+                // and not to confuse the StackScrollAlgorithm when it displays a HUN over GONE.
+                notificationStackScrolLView.get().apply {
+                    setStackTop(0f)
+                    setStackCutoff(0f)
+                }
+            }
+        }
+
         animateContentFloatAsState(
             value = QuickSettings.SharedValues.SquishinessValues.GoneSceneStarting,
             key = QuickSettings.SharedValues.TilesSquishiness,
@@ -75,9 +96,7 @@
         SnoozeableHeadsUpNotificationSpace(
             stackScrollView = notificationStackScrolLView.get(),
             viewModel =
-                rememberViewModel("GoneScene") {
-                    notificationsPlaceholderViewModelFactory.create()
-                },
+                rememberViewModel("GoneScene") { notificationsPlaceholderViewModelFactory.create() },
         )
     }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index 2d58c8c..c3dc84d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -39,6 +39,7 @@
 import com.android.compose.animation.scene.OverlayKey
 import com.android.compose.animation.scene.SceneKey
 import com.android.compose.animation.scene.SceneTransitionLayout
+import com.android.compose.animation.scene.SceneTransitions
 import com.android.compose.animation.scene.UserAction
 import com.android.compose.animation.scene.UserActionResult
 import com.android.compose.animation.scene.observableTransitionState
@@ -49,7 +50,6 @@
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
 import javax.inject.Provider
-import kotlinx.coroutines.flow.collectLatest
 
 /**
  * Renders a container of a collection of "scenes" that the user can switch between using certain
@@ -79,6 +79,7 @@
     sceneByKey: Map<SceneKey, Scene>,
     overlayByKey: Map<OverlayKey, Overlay>,
     initialSceneKey: SceneKey,
+    sceneTransitions: SceneTransitions,
     dataSourceDelegator: SceneDataSourceDelegator,
     qsSceneAdapter: Provider<QSSceneAdapter>,
     modifier: Modifier = Modifier,
@@ -88,7 +89,7 @@
         MutableSceneTransitionLayoutState(
             initialScene = initialSceneKey,
             canChangeScene = { toScene -> viewModel.canChangeScene(toScene) },
-            transitions = SceneContainerTransitions,
+            transitions = sceneTransitions,
         )
     }
 
@@ -117,7 +118,7 @@
                 ) {
                     "invalid ContentKey: $actionableContentKey"
                 }
-            actionableContent.userActions.collectLatest { userActions ->
+            viewModel.filteredUserActions(actionableContent.userActions).collect { userActions ->
                 userActionsByContentKey[actionableContentKey] =
                     viewModel.resolveSceneFamilies(userActions)
             }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
index 05a0119..bfcde7d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
@@ -130,10 +130,6 @@
     modifier: Modifier = Modifier,
 ) {
     val viewModel = rememberViewModel("CollapsedShadeHeader") { viewModelFactory.create() }
-    val isDisabled by viewModel.isDisabled.collectAsStateWithLifecycle()
-    if (isDisabled) {
-        return
-    }
 
     val cutoutWidth = LocalDisplayCutout.current.width()
     val cutoutHeight = LocalDisplayCutout.current.height()
@@ -196,7 +192,7 @@
                             horizontalArrangement = Arrangement.End,
                             modifier =
                                 Modifier.element(ShadeHeader.Elements.CollapsedContentEnd)
-                                    .padding(horizontal = horizontalPadding)
+                                    .padding(horizontal = horizontalPadding),
                         ) {
                             if (isLargeScreenLayout) {
                                 ShadeCarrierGroup(
@@ -207,7 +203,7 @@
                             SystemIconContainer(
                                 viewModel = viewModel,
                                 isClickable = isLargeScreenLayout,
-                                modifier = Modifier.align(Alignment.CenterVertically)
+                                modifier = Modifier.align(Alignment.CenterVertically),
                             ) {
                                 StatusIcons(
                                     viewModel = viewModel,
@@ -217,7 +213,7 @@
                                     modifier =
                                         Modifier.align(Alignment.CenterVertically)
                                             .padding(end = 6.dp)
-                                            .weight(1f, fill = false)
+                                            .weight(1f, fill = false),
                                 )
                                 BatteryIcon(
                                     createBatteryMeterViewController =
@@ -252,27 +248,15 @@
                 CutoutLocation.NONE,
                 CutoutLocation.RIGHT -> {
                     startPlaceable.placeRelative(x = 0, y = 0)
-                    endPlaceable.placeRelative(
-                        x = startPlaceable.width,
-                        y = 0,
-                    )
+                    endPlaceable.placeRelative(x = startPlaceable.width, y = 0)
                 }
                 CutoutLocation.CENTER -> {
                     startPlaceable.placeRelative(x = 0, y = 0)
-                    endPlaceable.placeRelative(
-                        x = startPlaceable.width + cutoutWidthPx,
-                        y = 0,
-                    )
+                    endPlaceable.placeRelative(x = startPlaceable.width + cutoutWidthPx, y = 0)
                 }
                 CutoutLocation.LEFT -> {
-                    startPlaceable.placeRelative(
-                        x = cutoutWidthPx,
-                        y = 0,
-                    )
-                    endPlaceable.placeRelative(
-                        x = startPlaceable.width + cutoutWidthPx,
-                        y = 0,
-                    )
+                    startPlaceable.placeRelative(x = cutoutWidthPx, y = 0)
+                    endPlaceable.placeRelative(x = startPlaceable.width + cutoutWidthPx, y = 0)
                 }
             }
         }
@@ -288,10 +272,6 @@
     modifier: Modifier = Modifier,
 ) {
     val viewModel = rememberViewModel("ExpandedShadeHeader") { viewModelFactory.create() }
-    val isDisabled by viewModel.isDisabled.collectAsStateWithLifecycle()
-    if (isDisabled) {
-        return
-    }
 
     val useExpandedFormat by remember {
         derivedStateOf { shouldUseExpandedFormat(layoutState.transitionState) }
@@ -302,17 +282,14 @@
     Box(modifier = modifier.sysuiResTag(ShadeHeader.TestTags.Root)) {
         if (isPrivacyChipVisible) {
             Box(modifier = Modifier.height(CollapsedHeight).fillMaxWidth()) {
-                PrivacyChip(
-                    viewModel = viewModel,
-                    modifier = Modifier.align(Alignment.CenterEnd),
-                )
+                PrivacyChip(viewModel = viewModel, modifier = Modifier.align(Alignment.CenterEnd))
             }
         }
         Column(
             verticalArrangement = Arrangement.Bottom,
             modifier =
                 Modifier.fillMaxWidth()
-                    .defaultMinSize(minHeight = ShadeHeader.Dimensions.ExpandedHeight)
+                    .defaultMinSize(minHeight = ShadeHeader.Dimensions.ExpandedHeight),
         ) {
             Box(modifier = Modifier.fillMaxWidth()) {
                 Box {
@@ -362,11 +339,7 @@
 }
 
 @Composable
-private fun SceneScope.Clock(
-    scale: Float,
-    viewModel: ShadeHeaderViewModel,
-    modifier: Modifier,
-) {
+private fun SceneScope.Clock(scale: Float, viewModel: ShadeHeaderViewModel, modifier: Modifier) {
     val layoutDirection = LocalLayoutDirection.current
 
     Element(key = ShadeHeader.Elements.Clock, modifier = modifier) {
@@ -391,10 +364,10 @@
                                     LayoutDirection.Ltr -> 0f
                                     LayoutDirection.Rtl -> 1f
                                 },
-                                0.5f
+                                0.5f,
                             )
                     }
-                    .clickable { viewModel.onClockClicked() }
+                    .clickable { viewModel.onClockClicked() },
         )
     }
 }
@@ -447,10 +420,7 @@
 }
 
 @Composable
-private fun ShadeCarrierGroup(
-    viewModel: ShadeHeaderViewModel,
-    modifier: Modifier = Modifier,
-) {
+private fun ShadeCarrierGroup(viewModel: ShadeHeaderViewModel, modifier: Modifier = Modifier) {
     Row(modifier = modifier) {
         val subIds by viewModel.mobileSubIds.collectAsStateWithLifecycle()
 
@@ -465,11 +435,11 @@
                             viewModel =
                                 (viewModel.mobileIconsViewModel.viewModelForSub(
                                     subId,
-                                    StatusBarLocation.SHADE_CARRIER_GROUP
+                                    StatusBarLocation.SHADE_CARRIER_GROUP,
                                 ) as ShadeCarrierGroupMobileIconViewModel),
                         )
                         .also { it.setOnClickListener { viewModel.onShadeCarrierGroupClicked() } }
-                },
+                }
             )
         }
     }
@@ -506,7 +476,7 @@
                 Utils.getColorAttrDefaultColor(themedContext, android.R.attr.textColorPrimary),
                 Utils.getColorAttrDefaultColor(
                     themedContext,
-                    android.R.attr.textColorPrimaryInverse
+                    android.R.attr.textColorPrimaryInverse,
                 ),
             )
             statusBarIconController.addIconGroup(iconManager)
@@ -551,7 +521,7 @@
     viewModel: ShadeHeaderViewModel,
     isClickable: Boolean,
     modifier: Modifier = Modifier,
-    content: @Composable RowScope.() -> Unit
+    content: @Composable RowScope.() -> Unit,
 ) {
     val interactionSource = remember { MutableInteractionSource() }
     val isHovered by interactionSource.collectIsHoveredAsState()
@@ -578,10 +548,7 @@
 }
 
 @Composable
-private fun SceneScope.PrivacyChip(
-    viewModel: ShadeHeaderViewModel,
-    modifier: Modifier = Modifier,
-) {
+private fun SceneScope.PrivacyChip(viewModel: ShadeHeaderViewModel, modifier: Modifier = Modifier) {
     val privacyList by viewModel.privacyItems.collectAsStateWithLifecycle()
 
     AndroidView(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index bba3d69..22b6dbc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -270,6 +270,7 @@
         )
     val isEmptySpaceClickable by viewModel.isEmptySpaceClickable.collectAsStateWithLifecycle()
     val isMediaVisible by viewModel.isMediaVisible.collectAsStateWithLifecycle()
+    val isQsEnabled by viewModel.isQsEnabled.collectAsStateWithLifecycle()
 
     val shouldPunchHoleBehindScrim =
         layoutState.isTransitioningBetween(Scenes.Gone, Scenes.Shade) ||
@@ -353,14 +354,26 @@
                     )
                 }
 
+                val qqsLayoutPaddingBottom =
+                    dimensionResource(id = R.dimen.qqs_layout_padding_bottom)
                 ShadeMediaCarousel(
                     isVisible = isMediaVisible,
                     isInRow = mediaInRow,
                     mediaHost = mediaHost,
                     mediaOffsetProvider = mediaOffsetProvider,
                     carouselController = mediaCarouselController,
-                    modifier = Modifier.layoutId(SingleShadeMeasurePolicy.LayoutId.Media),
+                    modifier =
+                        Modifier.layoutId(SingleShadeMeasurePolicy.LayoutId.Media)
+                            .padding(
+                                horizontal =
+                                    shadeHorizontalPadding +
+                                        dimensionResource(id = R.dimen.qs_horizontal_margin)
+                            )
+                            .thenIf(!mediaInRow) {
+                                Modifier.padding(bottom = qqsLayoutPaddingBottom)
+                            },
                     usingCollapsedLandscapeMedia = usingCollapsedLandscapeMedia,
+                    isQsEnabled = isQsEnabled,
                     isInSplitShade = false,
                 )
 
@@ -416,6 +429,7 @@
     val screenCornerRadius = LocalScreenCornerRadius.current
 
     val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsStateWithLifecycle()
+    val isQsEnabled by viewModel.isQsEnabled.collectAsStateWithLifecycle()
     val isCustomizerShowing by
         viewModel.qsSceneAdapter.isCustomizerShowing.collectAsStateWithLifecycle()
     val customizingAnimationDuration by
@@ -562,11 +576,16 @@
                                 mediaOffsetProvider = mediaOffsetProvider,
                                 modifier =
                                     Modifier.thenIf(
-                                        MediaContentPicker.shouldElevateMedia(layoutState)
-                                    ) {
-                                        Modifier.zIndex(1f)
-                                    },
+                                            MediaContentPicker.shouldElevateMedia(layoutState)
+                                        ) {
+                                            Modifier.zIndex(1f)
+                                        }
+                                        .padding(
+                                            horizontal =
+                                                dimensionResource(id = R.dimen.qs_horizontal_margin)
+                                        ),
                                 carouselController = mediaCarouselController,
+                                isQsEnabled = isQsEnabled,
                                 isInSplitShade = true,
                             )
                         }
@@ -620,10 +639,14 @@
     mediaHost: MediaHost,
     carouselController: MediaCarouselController,
     mediaOffsetProvider: ShadeMediaOffsetProvider,
+    isInSplitShade: Boolean,
+    isQsEnabled: Boolean,
     modifier: Modifier = Modifier,
     usingCollapsedLandscapeMedia: Boolean = false,
-    isInSplitShade: Boolean,
 ) {
+    if (!isQsEnabled) {
+        return
+    }
     MediaCarousel(
         modifier = modifier.fillMaxWidth(),
         isVisible = isVisible,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index eb2a016..e819bfd 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -53,10 +53,10 @@
 import com.android.compose.animation.scene.transformation.CustomPropertyTransformation
 import com.android.compose.animation.scene.transformation.InterpolatedPropertyTransformation
 import com.android.compose.animation.scene.transformation.PropertyTransformation
-import com.android.compose.animation.scene.transformation.SharedElementTransformation
 import com.android.compose.animation.scene.transformation.TransformationWithRange
 import com.android.compose.modifiers.thenIf
 import com.android.compose.ui.graphics.drawInContainer
+import com.android.compose.ui.util.IntIndexedMap
 import com.android.compose.ui.util.lerp
 import kotlin.math.roundToInt
 import kotlinx.coroutines.launch
@@ -70,6 +70,14 @@
     val stateByContent = SnapshotStateMap<ContentKey, State>()
 
     /**
+     * A sorted map of nesting depth (key) to content key (value). For shared elements it is used to
+     * determine which content this element should be rendered by. The nesting depth refers to the
+     * number of STLs nested within each other, starting at 0 for the parent STL and increasing by
+     * one for each nested [NestedSceneTransitionLayout].
+     */
+    val renderAuthority = IntIndexedMap<ContentKey>()
+
+    /**
      * The last transition that was used when computing the state (size, position and alpha) of this
      * element in any content, or `null` if it was last laid out when idle.
      */
@@ -232,9 +240,8 @@
     private val element: Element
         get() = _element!!
 
-    private var _stateInContent: Element.State? = null
     private val stateInContent: Element.State
-        get() = _stateInContent!!
+        get() = element.stateByContent.getValue(content.key)
 
     override val traverseKey: Any = ElementTraverseKey
 
@@ -248,9 +255,13 @@
         val element =
             layoutImpl.elements[key] ?: Element(key).also { layoutImpl.elements[key] = it }
         _element = element
-        _stateInContent =
-            element.stateByContent[content.key]
-                ?: Element.State(content.key).also { element.stateByContent[content.key] = it }
+        addToRenderAuthority(element)
+        if (!element.stateByContent.contains(content.key)) {
+            val elementState = Element.State(content.key)
+            element.stateByContent[content.key] = elementState
+
+            layoutImpl.ancestorContentKeys.forEach { element.stateByContent[it] = elementState }
+        }
     }
 
     private fun addNodeToContentState() {
@@ -272,8 +283,20 @@
         removeNodeFromContentState()
         maybePruneMaps(layoutImpl, element, stateInContent)
 
+        removeFromRenderAuthority()
         _element = null
-        _stateInContent = null
+    }
+
+    private fun addToRenderAuthority(element: Element) {
+        val nestingDepth = layoutImpl.ancestorContentKeys.size
+        element.renderAuthority[nestingDepth] = content.key
+    }
+
+    private fun removeFromRenderAuthority() {
+        val nestingDepth = layoutImpl.ancestorContentKeys.size
+        if (element.renderAuthority[nestingDepth] == content.key) {
+            element.renderAuthority.remove(nestingDepth)
+        }
     }
 
     private fun removeNodeFromContentState() {
@@ -346,15 +369,17 @@
         val elementState = elementState(layoutImpl, element, currentTransitionStates)
         if (elementState == null) {
             // If the element is not part of any transition, place it normally in its idle scene.
+            // This is the case if for example a transition between two overlays is ongoing where
+            // sharedElement isn't part of either but the element is still rendered as part of
+            // the underlying scene that is currently not being transitioned.
             val currentState = currentTransitionStates.last()
-            val placeInThisContent =
+            val shouldPlaceInThisContent =
                 elementContentWhenIdle(
                     layoutImpl,
                     currentState,
                     isInContent = { it in element.stateByContent },
                 ) == content.key
-
-            return if (placeInThisContent) {
+            return if (shouldPlaceInThisContent) {
                 placeNormally(measurable, constraints)
             } else {
                 doNotPlace(measurable, constraints)
@@ -536,7 +561,9 @@
 
         stateInContent.clearLastPlacementValues()
         traverseDescendants(ElementTraverseKey) { node ->
-            (node as ElementNode)._stateInContent?.clearLastPlacementValues()
+            if ((node as ElementNode)._element != null) {
+                node.stateInContent.clearLastPlacementValues()
+            }
             TraversableNode.Companion.TraverseDescendantsAction.ContinueTraversal
         }
     }
@@ -569,22 +596,30 @@
             element: Element,
             stateInContent: Element.State,
         ) {
-            // If element is not composed in this content anymore, remove the content values. This
-            // works because [onAttach] is called before [onDetach], so if an element is moved from
-            // the UI tree we will first add the new code location then remove the old one.
-            if (
-                stateInContent.nodes.isEmpty() &&
-                    element.stateByContent[stateInContent.content] == stateInContent
-            ) {
-                element.stateByContent.remove(stateInContent.content)
-
-                // If the element is not composed in any content, remove it from the elements map.
+            fun pruneForContent(contentKey: ContentKey) {
+                // If element is not composed in this content anymore, remove the content values.
+                // This works because [onAttach] is called before [onDetach], so if an element is
+                // moved from the UI tree we will first add the new code location then remove the
+                // old one.
                 if (
-                    element.stateByContent.isEmpty() && layoutImpl.elements[element.key] == element
+                    stateInContent.nodes.isEmpty() &&
+                        element.stateByContent[contentKey] == stateInContent
                 ) {
-                    layoutImpl.elements.remove(element.key)
+                    element.stateByContent.remove(contentKey)
+
+                    // If the element is not composed in any content, remove it from the elements
+                    // map.
+                    if (
+                        element.stateByContent.isEmpty() &&
+                            layoutImpl.elements[element.key] == element
+                    ) {
+                        layoutImpl.elements.remove(element.key)
+                    }
                 }
             }
+
+            pruneForContent(stateInContent.content)
+            layoutImpl.ancestorContentKeys.forEach { content -> pruneForContent(content) }
         }
     }
 }
@@ -890,12 +925,13 @@
     val transition =
         when (elementState) {
             is TransitionState.Idle -> {
-                return content ==
-                    elementContentWhenIdle(
-                        layoutImpl,
-                        elementState,
-                        isInContent = { it in element.stateByContent },
-                    )
+                return element.shouldBeRenderedBy(content) &&
+                    content ==
+                        elementContentWhenIdle(
+                            layoutImpl,
+                            elementState,
+                            isInContent = { it in element.stateByContent },
+                        )
             }
             is TransitionState.Transition -> elementState
         }
@@ -925,76 +961,7 @@
         return true
     }
 
-    return shouldPlaceOrComposeSharedElement(
-        layoutImpl,
-        content,
-        element.key,
-        transition,
-        isInContent = { it in element.stateByContent },
-    )
-}
-
-internal inline fun shouldPlaceOrComposeSharedElement(
-    layoutImpl: SceneTransitionLayoutImpl,
-    content: ContentKey,
-    element: ElementKey,
-    transition: TransitionState.Transition,
-    isInContent: (ContentKey) -> Boolean,
-): Boolean {
-    val overscrollContent = transition.currentOverscrollSpec?.content
-    if (overscrollContent != null) {
-        return when (transition) {
-            // If we are overscrolling between scenes, only place/compose the element in the
-            // overscrolling scene.
-            is TransitionState.Transition.ChangeScene -> content == overscrollContent
-
-            // If we are overscrolling an overlay, place/compose the element if [content] is the
-            // overscrolling content or if [content] is the current scene and the overscrolling
-            // overlay does not contain the element.
-            is TransitionState.Transition.ReplaceOverlay,
-            is TransitionState.Transition.ShowOrHideOverlay ->
-                content == overscrollContent ||
-                    (content == transition.currentScene && !isInContent(overscrollContent))
-        }
-    }
-
-    val scenePicker = element.contentPicker
-    val pickedScene =
-        scenePicker.contentDuringTransition(
-            element = element,
-            transition = transition,
-            fromContentZIndex = layoutImpl.content(transition.fromContent).zIndex,
-            toContentZIndex = layoutImpl.content(transition.toContent).zIndex,
-        )
-
-    return pickedScene == content
-}
-
-private fun isSharedElementEnabled(
-    element: ElementKey,
-    transition: TransitionState.Transition,
-): Boolean {
-    return sharedElementTransformation(element, transition)?.transformation?.enabled ?: true
-}
-
-internal fun sharedElementTransformation(
-    element: ElementKey,
-    transition: TransitionState.Transition,
-): TransformationWithRange<SharedElementTransformation>? {
-    val transformationSpec = transition.transformationSpec
-    val sharedInFromContent =
-        transformationSpec.transformations(element, transition.fromContent).shared
-    val sharedInToContent = transformationSpec.transformations(element, transition.toContent).shared
-
-    // The sharedElement() transformation must either be null or be the same in both contents.
-    if (sharedInFromContent != sharedInToContent) {
-        error(
-            "Different sharedElement() transformations matched $element " +
-                "(from=$sharedInFromContent to=$sharedInToContent)"
-        )
-    }
-
-    return sharedInFromContent
+    return shouldPlaceSharedElement(layoutImpl, content, element.key, transition)
 }
 
 /**
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
index 509a16c..17510c7 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
@@ -196,18 +196,54 @@
         is TransitionState.Transition -> {
             // During transitions, always compose movable elements in the scene picked by their
             // content picker.
-            val contents = element.contentPicker.contents
-            shouldPlaceOrComposeSharedElement(
+            shouldComposeMoveableElement(
                 layoutImpl,
                 content,
                 element,
                 elementState,
-                isInContent = { contents.contains(it) },
+                element.contentPicker.contents,
             )
         }
     }
 }
 
+private fun shouldComposeMoveableElement(
+    layoutImpl: SceneTransitionLayoutImpl,
+    content: ContentKey,
+    elementKey: ElementKey,
+    transition: TransitionState.Transition,
+    containingContents: Set<ContentKey>,
+): Boolean {
+    val overscrollContent = transition.currentOverscrollSpec?.content
+    if (overscrollContent != null) {
+        return when (transition) {
+            // If we are overscrolling between scenes, only place/compose the element in the
+            // overscrolling scene.
+            is TransitionState.Transition.ChangeScene -> content == overscrollContent
+
+            // If we are overscrolling an overlay, place/compose the element if [content] is the
+            // overscrolling content or if [content] is the current scene and the overscrolling
+            // overlay does not contain the element.
+            is TransitionState.Transition.ReplaceOverlay,
+            is TransitionState.Transition.ShowOrHideOverlay ->
+                content == overscrollContent ||
+                    (content == transition.currentScene &&
+                        !containingContents.contains(overscrollContent))
+        }
+    }
+
+    val scenePicker = elementKey.contentPicker
+    val pickedScene =
+        scenePicker.contentDuringTransition(
+            element = elementKey,
+            transition = transition,
+            fromContentZIndex = layoutImpl.content(transition.fromContent).zIndex,
+            toContentZIndex = layoutImpl.content(transition.toContent).zIndex,
+        )
+
+    return pickedScene == content
+}
+
 private fun movableElementState(
     element: MovableElementKey,
     transitionStates: List<TransitionState>,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index 1d3418b..759100b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -28,6 +28,7 @@
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
 import androidx.compose.ui.input.pointer.PointerType
+import androidx.compose.ui.layout.LookaheadScope
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.unit.Density
@@ -68,7 +69,7 @@
         swipeDetector,
         transitionInterceptionThreshold,
         onLayoutImpl = null,
-        builder,
+        builder = builder,
     )
 }
 
@@ -261,6 +262,18 @@
      * lists keep a constant size during transitions even if its elements are growing/shrinking.
      */
     fun Modifier.noResizeDuringTransitions(): Modifier
+
+    /**
+     * A [NestedSceneTransitionLayout] will share its elements with its ancestor STLs therefore
+     * enabling sharedElement transitions between them.
+     */
+    // TODO(b/380070506): Add more parameters when default params are supported in Kotlin 2.0.21
+    @Composable
+    fun NestedSceneTransitionLayout(
+        state: SceneTransitionLayoutState,
+        modifier: Modifier,
+        builder: SceneTransitionLayoutScope.() -> Unit,
+    )
 }
 
 @Deprecated("Use ContentScope instead", ReplaceWith("ContentScope"))
@@ -678,6 +691,9 @@
     swipeDetector: SwipeDetector = DefaultSwipeDetector,
     transitionInterceptionThreshold: Float = 0f,
     onLayoutImpl: ((SceneTransitionLayoutImpl) -> Unit)? = null,
+    sharedElementMap: MutableMap<ElementKey, Element> = remember { mutableMapOf() },
+    ancestorContentKeys: List<ContentKey> = emptyList(),
+    lookaheadScope: LookaheadScope? = null,
     builder: SceneTransitionLayoutScope.() -> Unit,
 ) {
     val density = LocalDensity.current
@@ -692,6 +708,9 @@
                 transitionInterceptionThreshold = transitionInterceptionThreshold,
                 builder = builder,
                 animationScope = animationScope,
+                elements = sharedElementMap,
+                ancestorContentKeys = ancestorContentKeys,
+                lookaheadScope = lookaheadScope,
             )
             .also { onLayoutImpl?.invoke(it) }
     }
@@ -707,6 +726,24 @@
                     " that was used when creating it, which is not supported"
             )
         }
+        if (layoutImpl.elements != sharedElementMap) {
+            error(
+                "This SceneTransitionLayout was bound to a different elements map that was used " +
+                    "when creating it, which is not supported"
+            )
+        }
+        if (layoutImpl.ancestorContentKeys != ancestorContentKeys) {
+            error(
+                "This SceneTransitionLayout was bound to a different ancestorContents that was " +
+                    "used when creating it, which is not supported"
+            )
+        }
+        if (lookaheadScope != null && layoutImpl.lookaheadScope != lookaheadScope) {
+            error(
+                "This SceneTransitionLayout was bound to a different lookaheadScope that was " +
+                    "used when creating it, which is not supported"
+            )
+        }
 
         layoutImpl.density = density
         layoutImpl.layoutDirection = layoutDirection
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index b916b0b..bdc1461 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -70,7 +70,39 @@
      * animations.
      */
     internal val animationScope: CoroutineScope,
+
+    /**
+     * The map of [Element]s.
+     *
+     * Important: [Element]s from this map should never be accessed during composition because the
+     * Elements are added when the associated Modifier.element() node is attached to the Modifier
+     * tree, i.e. after composition.
+     */
+    internal val elements: MutableMap<ElementKey, Element> = mutableMapOf(),
+
+    /**
+     * When this STL is a [NestedSceneTransitionLayout], this is a list of [ContentKey]s of where
+     * this STL is composed in within its ancestors.
+     *
+     * The root STL holds an emptyList. With each nesting level the parent is supposed to add
+     * exactly one scene to the list, therefore the size of this list is equal to the nesting depth
+     * of this STL.
+     *
+     * This is used to know in which content of the ancestors a sharedElement appears in.
+     */
+    internal val ancestorContentKeys: List<ContentKey> = emptyList(),
+    lookaheadScope: LookaheadScope? = null,
 ) {
+
+    /**
+     * The [LookaheadScope] of this layout, that can be used to compute offsets relative to the
+     * layout. For [NestedSceneTransitionLayout]s this scope is the scope of the root STL, such that
+     * offset computations can be shared among all children.
+     */
+    private var _lookaheadScope: LookaheadScope? = lookaheadScope
+    internal val lookaheadScope: LookaheadScope
+        get() = _lookaheadScope!!
+
     /**
      * The map of [Scene]s.
      *
@@ -89,15 +121,6 @@
         get() = _overlays ?: SnapshotStateMap<OverlayKey, Overlay>().also { _overlays = it }
 
     /**
-     * The map of [Element]s.
-     *
-     * Important: [Element]s from this map should never be accessed during composition because the
-     * Elements are added when the associated Modifier.element() node is attached to the Modifier
-     * tree, i.e. after composition.
-     */
-    internal val elements = mutableMapOf<ElementKey, Element>()
-
-    /**
      * The map of contents of movable elements.
      *
      * Note that given that this map is mutated directly during a composition, it has to be a
@@ -138,13 +161,6 @@
                     _userActionDistanceScope = it
                 }
 
-    /**
-     * The [LookaheadScope] of this layout, that can be used to compute offsets relative to the
-     * layout.
-     */
-    internal lateinit var lookaheadScope: LookaheadScope
-        private set
-
     internal var lastSize: IntSize = IntSize.Zero
 
     init {
@@ -347,7 +363,12 @@
                 .then(LayoutElement(layoutImpl = this))
         ) {
             LookaheadScope {
-                lookaheadScope = this
+                if (_lookaheadScope == null) {
+                    // We can't init this in a SideEffect as other NestedSTLs are already calling
+                    // this during composition. However, when composition is canceled
+                    // SceneTransitionLayoutImpl is discarded as well. So it's fine to do this here.
+                    _lookaheadScope = this
+                }
 
                 BackHandler()
                 Scenes()
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt
new file mode 100644
index 0000000..599a152a
--- /dev/null
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt
@@ -0,0 +1,113 @@
+/*
+ * 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.compose.animation.scene
+
+import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.animation.scene.transformation.SharedElementTransformation
+import com.android.compose.animation.scene.transformation.TransformationWithRange
+
+/**
+ * Whether this element should be rendered by the given [content]. This method returns true only for
+ * exactly one content at any given time.
+ */
+internal fun Element.shouldBeRenderedBy(content: ContentKey): Boolean {
+    // The current strategy is that always the content with the lowest nestingDepth has authority.
+    // This content is supposed to render the shared element because this is also the level at which
+    // the transition is running. If the [renderAuthority.size] is 1 it means that that this element
+    // is currently composed only in one nesting level, which means that the render authority
+    // is determined by "classic" shared element code.
+    return renderAuthority.size == 1 || renderAuthority.first() == content
+}
+
+/**
+ * Whether this element is currently composed in multiple [SceneTransitionLayout]s.
+ *
+ * Note: Shared elements across [NestedSceneTransitionLayout]s side-by-side are not supported.
+ */
+internal fun Element.isPresentInMultipleStls(): Boolean {
+    return renderAuthority.size > 1
+}
+
+internal fun shouldPlaceSharedElement(
+    layoutImpl: SceneTransitionLayoutImpl,
+    content: ContentKey,
+    elementKey: ElementKey,
+    transition: TransitionState.Transition,
+): Boolean {
+    val element = layoutImpl.elements.getValue(elementKey)
+    if (element.isPresentInMultipleStls()) {
+        // If the element is present in multiple STLs we require the highest STL to render it and
+        // we don't want contentPicker to potentially return false for the highest STL.
+        return element.shouldBeRenderedBy(content)
+    }
+
+    val overscrollContent = transition.currentOverscrollSpec?.content
+    if (overscrollContent != null) {
+        return when (transition) {
+            // If we are overscrolling between scenes, only place/compose the element in the
+            // overscrolling scene.
+            is TransitionState.Transition.ChangeScene -> content == overscrollContent
+
+            // If we are overscrolling an overlay, place/compose the element if [content] is the
+            // overscrolling content or if [content] is the current scene and the overscrolling
+            // overlay does not contain the element.
+            is TransitionState.Transition.ReplaceOverlay,
+            is TransitionState.Transition.ShowOrHideOverlay ->
+                content == overscrollContent ||
+                    (content == transition.currentScene &&
+                        overscrollContent !in element.stateByContent)
+        }
+    }
+
+    val scenePicker = elementKey.contentPicker
+    val pickedScene =
+        scenePicker.contentDuringTransition(
+            element = elementKey,
+            transition = transition,
+            fromContentZIndex = layoutImpl.content(transition.fromContent).zIndex,
+            toContentZIndex = layoutImpl.content(transition.toContent).zIndex,
+        )
+
+    return pickedScene == content
+}
+
+internal fun isSharedElementEnabled(
+    element: ElementKey,
+    transition: TransitionState.Transition,
+): Boolean {
+    return sharedElementTransformation(element, transition)?.transformation?.enabled ?: true
+}
+
+internal fun sharedElementTransformation(
+    element: ElementKey,
+    transition: TransitionState.Transition,
+): TransformationWithRange<SharedElementTransformation>? {
+    val transformationSpec = transition.transformationSpec
+    val sharedInFromContent =
+        transformationSpec.transformations(element, transition.fromContent).shared
+    val sharedInToContent = transformationSpec.transformations(element, transition.toContent).shared
+
+    // The sharedElement() transformation must either be null or be the same in both contents.
+    if (sharedInFromContent != sharedInToContent) {
+        error(
+            "Different sharedElement() transformations matched $element " +
+                "(from=$sharedInFromContent to=$sharedInToContent)"
+        )
+    }
+
+    return sharedInFromContent
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
index 255a16c..8c4cd8c 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
@@ -23,6 +23,7 @@
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableFloatStateOf
 import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.layout.approachLayout
@@ -41,7 +42,9 @@
 import com.android.compose.animation.scene.MovableElementContentScope
 import com.android.compose.animation.scene.MovableElementKey
 import com.android.compose.animation.scene.NestedScrollBehavior
+import com.android.compose.animation.scene.SceneTransitionLayoutForTesting
 import com.android.compose.animation.scene.SceneTransitionLayoutImpl
+import com.android.compose.animation.scene.SceneTransitionLayoutScope
 import com.android.compose.animation.scene.SceneTransitionLayoutState
 import com.android.compose.animation.scene.SharedValueType
 import com.android.compose.animation.scene.UserAction
@@ -175,4 +178,24 @@
     override fun Modifier.noResizeDuringTransitions(): Modifier {
         return noResizeDuringTransitions(layoutState = layoutImpl.state)
     }
+
+    @Composable
+    override fun NestedSceneTransitionLayout(
+        state: SceneTransitionLayoutState,
+        modifier: Modifier,
+        builder: SceneTransitionLayoutScope.() -> Unit,
+    ) {
+        SceneTransitionLayoutForTesting(
+            state,
+            modifier,
+            onLayoutImpl = null,
+            builder = builder,
+            sharedElementMap = layoutImpl.elements,
+            ancestorContentKeys =
+                remember(layoutImpl.ancestorContentKeys, contentKey) {
+                    layoutImpl.ancestorContentKeys + contentKey
+                },
+            lookaheadScope = layoutImpl.lookaheadScope,
+        )
+    }
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/ui/util/IntIndexedMap.kt b/packages/SystemUI/compose/scene/src/com/android/compose/ui/util/IntIndexedMap.kt
new file mode 100644
index 0000000..1b5341b
--- /dev/null
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/ui/util/IntIndexedMap.kt
@@ -0,0 +1,73 @@
+/*
+ * 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.compose.ui.util
+
+/**
+ * This is a custom implementation that resembles a SortedMap<Int, T> but is based on a simple
+ * ArrayList to avoid the allocation overhead and boxing.
+ *
+ * It can only hold positive keys and 0 and it is only efficient for small keys (0 - ~100), but
+ * therefore provides fast operations for small keys.
+ */
+internal class IntIndexedMap<T> {
+    private val arrayList = ArrayList<T?>()
+    private var _size = 0
+    val size
+        get() = _size
+
+    /** Returns the value at [key] or null if the key is not present. */
+    operator fun get(key: Int): T? {
+        if (key < 0 || key >= arrayList.size) return null
+        return arrayList[key]
+    }
+
+    /**
+     * Sets the value at [key] to [value]. If [key] is larger than the current size of the map, this
+     * operation may take up to O(key) time and space. Therefore this data structure is only
+     * efficient for small [key] sizes.
+     */
+    operator fun set(key: Int, value: T?) {
+        if (key < 0)
+            throw UnsupportedOperationException("This map can only hold positive keys and 0.")
+        if (key < arrayList.size) {
+            if (arrayList[key] != null && value == null) _size--
+            if (arrayList[key] == null && value != null) _size++
+            arrayList[key] = value
+        } else {
+            if (value == null) return
+            while (key > arrayList.size) {
+                arrayList.add(null)
+            }
+            _size++
+            arrayList.add(value)
+        }
+    }
+
+    /** Remove value at [key] */
+    fun remove(key: Int) {
+        if (key >= arrayList.size) return
+        this[key] = null
+    }
+
+    /** Get the [value] with the smallest [key] of the map. */
+    fun first(): T {
+        for (i in 0 until arrayList.size) {
+            return arrayList[i] ?: continue
+        }
+        throw NoSuchElementException("The map is empty.")
+    }
+}
diff --git a/packages/SystemUI/compose/scene/tests/AndroidManifest.xml b/packages/SystemUI/compose/scene/tests/AndroidManifest.xml
index 174ad30..2b76d7b 100644
--- a/packages/SystemUI/compose/scene/tests/AndroidManifest.xml
+++ b/packages/SystemUI/compose/scene/tests/AndroidManifest.xml
@@ -18,7 +18,8 @@
     package="com.android.compose.animation.scene.tests" >
 
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
-    <application>
+    <application
+        android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
         <uses-library android:name="android.test.runner" />
     </application>
 
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedSharedElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedSharedElementTest.kt
new file mode 100644
index 0000000..c6ef8cf
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedSharedElementTest.kt
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene.transformation
+
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.test.assertIsNotDisplayed
+import androidx.compose.ui.test.assertPositionInRootIsEqualTo
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.AutoTransitionTestAssertionScope
+import com.android.compose.animation.scene.ContentScope
+import com.android.compose.animation.scene.Default4FrameLinearTransition
+import com.android.compose.animation.scene.Edge
+import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.TestElements
+import com.android.compose.animation.scene.TestScenes
+import com.android.compose.animation.scene.inScene
+import com.android.compose.animation.scene.testTransition
+import com.android.compose.animation.scene.transitions
+import com.android.compose.test.assertSizeIsEqualTo
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class NestedSharedElementTest {
+    @get:Rule val rule = createComposeRule()
+
+    private object Scenes {
+        val NestedSceneA = SceneKey("NestedSceneA")
+        val NestedSceneB = SceneKey("NestedSceneB")
+        val NestedNestedSceneA = SceneKey("NestedNestedSceneA")
+        val NestedNestedSceneB = SceneKey("NestedNestedSceneB")
+    }
+
+    private val elementVariant1 = SharedElement(0.dp, 0.dp, 100.dp, 100.dp, Color.Red)
+    private val elementVariant2 = SharedElement(40.dp, 80.dp, 60.dp, 20.dp, Color.Blue)
+    private val elementVariant3 = SharedElement(80.dp, 40.dp, 140.dp, 180.dp, Color.Yellow)
+    private val elementVariant4 = SharedElement(120.dp, 240.dp, 20.dp, 140.dp, Color.Green)
+
+    private class SharedElement(
+        val x: Dp,
+        val y: Dp,
+        val width: Dp,
+        val height: Dp,
+        val color: Color = Color.Black,
+        val alpha: Float = 0.8f,
+    )
+
+    @Composable
+    private fun ContentScope.SharedElement(element: SharedElement) {
+        Box(Modifier.fillMaxSize()) {
+            Box(
+                Modifier.offset(element.x, element.y)
+                    .element(TestElements.Foo)
+                    .size(element.width, element.height)
+                    .background(element.color)
+                    .alpha(element.alpha)
+            )
+        }
+    }
+
+    private val contentWithSharedElement: @Composable ContentScope.() -> Unit = {
+        SharedElement(elementVariant1)
+    }
+
+    private val nestedState: MutableSceneTransitionLayoutState =
+        rule.runOnUiThread {
+            MutableSceneTransitionLayoutState(
+                Scenes.NestedSceneA,
+                transitions {
+                    from(
+                        from = Scenes.NestedSceneA,
+                        to = Scenes.NestedSceneB,
+                        builder = Default4FrameLinearTransition,
+                    )
+                },
+            )
+        }
+
+    private val nestedNestedState: MutableSceneTransitionLayoutState =
+        rule.runOnUiThread {
+            MutableSceneTransitionLayoutState(
+                Scenes.NestedNestedSceneA,
+                transitions {
+                    from(
+                        from = Scenes.NestedNestedSceneA,
+                        to = Scenes.NestedNestedSceneB,
+                        builder = Default4FrameLinearTransition,
+                    )
+                },
+            )
+        }
+
+    private val nestedStlWithSharedElement: @Composable ContentScope.() -> Unit = {
+        NestedSceneTransitionLayout(nestedState, modifier = Modifier) {
+            scene(Scenes.NestedSceneA) { SharedElement(elementVariant2) }
+            scene(Scenes.NestedSceneB) { SharedElement(elementVariant3) }
+        }
+    }
+
+    private val nestedNestedStlWithSharedElement: @Composable ContentScope.() -> Unit = {
+        NestedSceneTransitionLayout(nestedState, modifier = Modifier) {
+            scene(Scenes.NestedSceneA) {
+                NestedSceneTransitionLayout(state = nestedNestedState, modifier = Modifier) {
+                    scene(Scenes.NestedNestedSceneA) { SharedElement(elementVariant4) }
+                    scene(Scenes.NestedNestedSceneB) { SharedElement(elementVariant3) }
+                }
+            }
+            scene(Scenes.NestedSceneB) { SharedElement(elementVariant2) }
+        }
+    }
+
+    @Test
+    fun nestedSharedElementTransition_fromNestedSTLtoParentSTL() {
+        rule.testTransition(
+            fromSceneContent = nestedStlWithSharedElement,
+            toSceneContent = contentWithSharedElement,
+        ) {
+            before { onElement(TestElements.Foo).assertElementVariant(elementVariant2) }
+            atAllFrames(4) {
+                onElement(TestElements.Foo, TestScenes.SceneA).assertIsNotDisplayed()
+
+                onElement(TestElements.Foo, TestScenes.SceneB)
+                    .assertBetweenElementVariants(elementVariant2, elementVariant1, this)
+            }
+            after { onElement(TestElements.Foo).assertElementVariant(elementVariant1) }
+        }
+    }
+
+    @Test
+    fun nestedSharedElementTransition_fromParentSTLtoNestedSTL() {
+        rule.testTransition(
+            fromSceneContent = contentWithSharedElement,
+            toSceneContent = nestedStlWithSharedElement,
+        ) {
+            before { onElement(TestElements.Foo).assertElementVariant(elementVariant1) }
+            atAllFrames(4) {
+                onElement(TestElements.Foo, TestScenes.SceneB).assertIsNotDisplayed()
+
+                onElement(TestElements.Foo, TestScenes.SceneA)
+                    .assertBetweenElementVariants(elementVariant1, elementVariant2, this)
+            }
+            after { onElement(TestElements.Foo).assertElementVariant(elementVariant2) }
+        }
+    }
+
+    @Test
+    fun nestedSharedElementTransition_fromParentSTLtoNestedNestedSTL() {
+        rule.testTransition(
+            fromSceneContent = contentWithSharedElement,
+            toSceneContent = nestedNestedStlWithSharedElement,
+        ) {
+            before { onElement(TestElements.Foo).assertElementVariant(elementVariant1) }
+            atAllFrames(4) {
+                onElement(TestElements.Foo, TestScenes.SceneB).assertIsNotDisplayed()
+
+                onElement(TestElements.Foo, TestScenes.SceneA)
+                    .assertBetweenElementVariants(elementVariant1, elementVariant4, this)
+            }
+            after { onElement(TestElements.Foo).assertElementVariant(elementVariant4) }
+        }
+    }
+
+    @Test
+    fun nestedSharedElementTransition_fromNestedNestedSTLtoNestedSTL() {
+        rule.testTransition(
+            fromSceneContent = nestedNestedStlWithSharedElement,
+            toSceneContent = { Box(modifier = Modifier.fillMaxSize()) },
+            changeState = { nestedState.setTargetScene(Scenes.NestedSceneB, this) },
+        ) {
+            before { onElement(TestElements.Foo).assertElementVariant(elementVariant4) }
+            atAllFrames(4) {
+                onElement(TestElements.Foo, Scenes.NestedSceneA).assertIsNotDisplayed()
+                onElement(TestElements.Foo, Scenes.NestedNestedSceneA).assertIsNotDisplayed()
+
+                onElement(TestElements.Foo, Scenes.NestedSceneB)
+                    .assertBetweenElementVariants(elementVariant4, elementVariant2, this)
+            }
+            after { onElement(TestElements.Foo).assertElementVariant(elementVariant2) }
+        }
+    }
+
+    @Test
+    fun nestedSharedElement_sharedElementTransitionIsDisabled() {
+        rule.testTransition(
+            fromSceneContent = contentWithSharedElement,
+            toSceneContent = nestedStlWithSharedElement,
+            transition = {
+                spec = tween(16 * 4, easing = LinearEasing)
+
+                // Disable the shared element animation.
+                sharedElement(TestElements.Foo, enabled = false)
+
+                // In SceneA, Foo leaves to the left edge.
+                translate(TestElements.Foo.inScene(TestScenes.SceneA), Edge.Left, false)
+
+                // We can't reference the element inside the NestedSTL as of today
+            },
+        ) {
+            before { onElement(TestElements.Foo).assertElementVariant(elementVariant1) }
+            atAllFrames(4) {
+                onElement(TestElements.Foo, scene = TestScenes.SceneA)
+                    .assertPositionInRootIsEqualTo(
+                        interpolate(elementVariant1.x, 0.dp),
+                        elementVariant1.y,
+                    )
+                    .assertSizeIsEqualTo(elementVariant1.width, elementVariant1.height)
+            }
+            after { onElement(TestElements.Foo).assertElementVariant(elementVariant2) }
+        }
+    }
+
+    @Test
+    fun nestedSharedElementTransition_transitionInsideNestedStl() {
+        rule.testTransition(
+            layoutModifier = Modifier.fillMaxSize(),
+            fromSceneContent = nestedStlWithSharedElement,
+            toSceneContent = contentWithSharedElement,
+            changeState = { nestedState.setTargetScene(Scenes.NestedSceneB, animationScope = this) },
+        ) {
+            before { onElement(TestElements.Foo).assertElementVariant(elementVariant2) }
+            atAllFrames(4) {
+                onElement(TestElements.Foo, Scenes.NestedSceneA).assertIsNotDisplayed()
+
+                onElement(TestElements.Foo, scene = Scenes.NestedSceneB)
+                    .assertBetweenElementVariants(elementVariant2, elementVariant3, this)
+            }
+            after {
+                onElement(TestElements.Foo, Scenes.NestedSceneA).assertIsNotDisplayed()
+                onElement(TestElements.Foo).assertElementVariant(elementVariant3)
+            }
+        }
+    }
+
+    private fun SemanticsNodeInteraction.assertElementVariant(variant: SharedElement) {
+        assertPositionInRootIsEqualTo(variant.x, variant.y)
+        assertSizeIsEqualTo(variant.width, variant.height)
+    }
+
+    private fun SemanticsNodeInteraction.assertBetweenElementVariants(
+        from: SharedElement,
+        to: SharedElement,
+        assertScope: AutoTransitionTestAssertionScope,
+    ) {
+        assertPositionInRootIsEqualTo(
+            assertScope.interpolate(from.x, to.x),
+            assertScope.interpolate(from.y, to.y),
+        )
+        assertSizeIsEqualTo(
+            assertScope.interpolate(from.width, to.width),
+            assertScope.interpolate(from.height, to.height),
+        )
+    }
+}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/SharedElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/SharedElementTest.kt
index 2e3a934..47c10f5 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/SharedElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/SharedElementTest.kt
@@ -62,35 +62,14 @@
                 onElement(TestElements.Foo).assertPositionInRootIsEqualTo(10.dp, 50.dp)
                 onElement(TestElements.Foo).assertSizeIsEqualTo(20.dp, 80.dp)
             }
-            at(0) {
-                // Shared elements are by default placed and drawn only in the scene with highest
-                // zIndex.
+            atAllFrames(4) {
                 onElement(TestElements.Foo, TestScenes.SceneA).assertIsNotDisplayed()
-
                 onElement(TestElements.Foo, TestScenes.SceneB)
-                    .assertPositionInRootIsEqualTo(10.dp, 50.dp)
-                    .assertSizeIsEqualTo(20.dp, 80.dp)
-            }
-            at(16) {
-                onElement(TestElements.Foo, TestScenes.SceneA).assertIsNotDisplayed()
-
-                onElement(TestElements.Foo, TestScenes.SceneB)
-                    .assertPositionInRootIsEqualTo(20.dp, 55.dp)
-                    .assertSizeIsEqualTo(17.5.dp, 70.dp)
-            }
-            at(32) {
-                onElement(TestElements.Foo, TestScenes.SceneA).assertIsNotDisplayed()
-
-                onElement(TestElements.Foo, TestScenes.SceneB)
-                    .assertPositionInRootIsEqualTo(30.dp, 60.dp)
-                    .assertSizeIsEqualTo(15.dp, 60.dp)
-            }
-            at(48) {
-                onElement(TestElements.Foo, TestScenes.SceneA).assertIsNotDisplayed()
-
-                onElement(TestElements.Foo, TestScenes.SceneB)
-                    .assertPositionInRootIsEqualTo(40.dp, 65.dp)
-                    .assertSizeIsEqualTo(12.5.dp, 50.dp)
+                    .assertPositionInRootIsEqualTo(
+                        interpolate(10.dp, 50.dp),
+                        interpolate(50.dp, 70.dp),
+                    )
+                    .assertSizeIsEqualTo(interpolate(20.dp, 10.dp), interpolate(80.dp, 40.dp))
             }
             after {
                 onElement(TestElements.Foo).assertPositionInRootIsEqualTo(50.dp, 70.dp)
@@ -132,29 +111,11 @@
             },
         ) {
             before { onElement(TestElements.Foo).assertPositionInRootIsEqualTo(10.dp, 50.dp) }
-            at(0) {
+            atAllFrames(4) {
                 onElement(TestElements.Foo, scene = TestScenes.SceneA)
-                    .assertPositionInRootIsEqualTo(10.dp, 50.dp)
+                    .assertPositionInRootIsEqualTo(interpolate(10.dp, 0.dp), 50.dp)
                 onElement(TestElements.Foo, scene = TestScenes.SceneB)
-                    .assertPositionInRootIsEqualTo(50.dp, 100.dp)
-            }
-            at(16) {
-                onElement(TestElements.Foo, scene = TestScenes.SceneA)
-                    .assertPositionInRootIsEqualTo(7.5.dp, 50.dp)
-                onElement(TestElements.Foo, scene = TestScenes.SceneB)
-                    .assertPositionInRootIsEqualTo(50.dp, 90.dp)
-            }
-            at(32) {
-                onElement(TestElements.Foo, scene = TestScenes.SceneA)
-                    .assertPositionInRootIsEqualTo(5.dp, 50.dp)
-                onElement(TestElements.Foo, scene = TestScenes.SceneB)
-                    .assertPositionInRootIsEqualTo(50.dp, 80.dp)
-            }
-            at(48) {
-                onElement(TestElements.Foo, scene = TestScenes.SceneA)
-                    .assertPositionInRootIsEqualTo(2.5.dp, 50.dp)
-                onElement(TestElements.Foo, scene = TestScenes.SceneB)
-                    .assertPositionInRootIsEqualTo(50.dp, 70.dp)
+                    .assertPositionInRootIsEqualTo(50.dp, interpolate(100.dp, 60.dp))
             }
             after { onElement(TestElements.Foo).assertPositionInRootIsEqualTo(50.dp, 60.dp) }
         }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/ui/util/IntIndexMapTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/ui/util/IntIndexMapTest.kt
new file mode 100644
index 0000000..d7a9b90
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/ui/util/IntIndexMapTest.kt
@@ -0,0 +1,92 @@
+/*
+ * 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.compose.ui.util
+
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class IntIndexMapTest {
+
+    @Test
+    fun testSetGetFirstAndSize() {
+        val map = IntIndexedMap<String>()
+
+        // Write first element at 10
+        map[10] = "1"
+        assertThat(map[10]).isEqualTo("1")
+        assertThat(map.size).isEqualTo(1)
+        assertThat(map.first()).isEqualTo("1")
+
+        // Write same element to same index
+        map[10] = "1"
+        assertThat(map[10]).isEqualTo("1")
+        assertThat(map.size).isEqualTo(1)
+
+        // Writing into larger index
+        map[12] = "2"
+        assertThat(map[12]).isEqualTo("2")
+        assertThat(map.size).isEqualTo(2)
+        assertThat(map.first()).isEqualTo("1")
+
+        // Overwriting existing index
+        map[10] = "3"
+        assertThat(map[10]).isEqualTo("3")
+        assertThat(map.size).isEqualTo(2)
+        assertThat(map.first()).isEqualTo("3")
+
+        // Writing into smaller index
+        map[0] = "4"
+        assertThat(map[0]).isEqualTo("4")
+        assert(map.size == 3)
+        assertThat(map.first()).isEqualTo("4")
+
+        // Writing null into non-null index
+        map[0] = null
+        assertThat(map[0]).isEqualTo(null)
+        assertThat(map.size).isEqualTo(2)
+        assertThat(map.first()).isEqualTo("3")
+
+        // Writing null into smaller null index
+        map[1] = null
+        assertThat(map[1]).isEqualTo(null)
+        assertThat(map.size).isEqualTo(2)
+
+        // Writing null into larger null index
+        map[15] = null
+        assertThat(map[15]).isEqualTo(null)
+        assertThat(map.size).isEqualTo(2)
+
+        // Remove existing element
+        map.remove(12)
+        assertThat(map[12]).isEqualTo(null)
+        assertThat(map.size).isEqualTo(1)
+
+        // Remove non-existing element
+        map.remove(17)
+        assertThat(map[17]).isEqualTo(null)
+        assertThat(map.size).isEqualTo(1)
+
+        // Remove all elements
+        assertThat(map.first()).isEqualTo("3")
+        map.remove(10)
+        map.remove(10)
+        map.remove(0)
+        assertThat(map.size).isEqualTo(0)
+        assertThat(map[10]).isEqualTo(null)
+        assertThat(map.size).isEqualTo(0)
+    }
+}
diff --git a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt
index 0d2fcfc..124b61e 100644
--- a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt
+++ b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt
@@ -16,6 +16,8 @@
 
 package com.android.compose.animation.scene
 
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.tween
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.runtime.Composable
@@ -27,6 +29,9 @@
 import androidx.compose.ui.test.SemanticsNodeInteraction
 import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
 import androidx.compose.ui.test.junit4.ComposeContentTestRule
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.lerp
+import androidx.compose.ui.util.lerp
 import kotlinx.coroutines.CoroutineScope
 import platform.test.motion.MotionTestRule
 import platform.test.motion.RecordedMotion
@@ -62,6 +67,16 @@
     fun at(timestamp: Long, builder: TransitionTestAssertionScope.() -> Unit)
 
     /**
+     * Run the same assertion for all frames of a transition.
+     *
+     * @param totalFrames needs to be the exact number of frames of the transition that is run,
+     *   otherwise the passed progress will be incorrect. That is the duration in ms divided by 16.
+     * @param builder is passed a progress Float which can be used to calculate values for the
+     *   specific frame. Or use [AutoTransitionTestAssertionScope.interpolate].
+     */
+    fun atAllFrames(totalFrames: Int, builder: AutoTransitionTestAssertionScope.(Float) -> Unit)
+
+    /**
      * Assert on the state of the layout after the transition finished.
      *
      * This should be called maximum once, after [before] or [at] is called.
@@ -82,6 +97,16 @@
     fun onElement(element: ElementKey, scene: SceneKey? = null): SemanticsNodeInteraction
 }
 
+interface AutoTransitionTestAssertionScope : TransitionTestAssertionScope {
+
+    /** Linear interpolate [from] and [to] with the current progress of the transition. */
+    fun <T> interpolate(from: T, to: T): T
+}
+
+val Default4FrameLinearTransition: TransitionBuilder.() -> Unit = {
+    spec = tween(16 * 4, easing = LinearEasing)
+}
+
 /**
  * Test the transition between [fromSceneContent] and [toSceneContent] at different points in time.
  *
@@ -90,10 +115,13 @@
 fun ComposeContentTestRule.testTransition(
     fromSceneContent: @Composable ContentScope.() -> Unit,
     toSceneContent: @Composable ContentScope.() -> Unit,
-    transition: TransitionBuilder.() -> Unit,
+    transition: TransitionBuilder.() -> Unit = Default4FrameLinearTransition,
     layoutModifier: Modifier = Modifier,
     fromScene: SceneKey = TestScenes.SceneA,
     toScene: SceneKey = TestScenes.SceneB,
+    changeState: CoroutineScope.(MutableSceneTransitionLayoutState) -> Unit = { state ->
+        state.setTargetScene(toScene, animationScope = this)
+    },
     builder: TransitionTestBuilder.() -> Unit,
 ) {
     testTransition(
@@ -104,7 +132,7 @@
                     transitions { from(fromScene, to = toScene, builder = transition) },
                 )
             },
-        to = toScene,
+        changeState = changeState,
         transitionLayout = { state ->
             SceneTransitionLayout(state, layoutModifier) {
                 scene(fromScene, content = fromSceneContent)
@@ -293,13 +321,30 @@
 ) {
     val test = transitionTest(builder)
     val assertionScope =
-        object : TransitionTestAssertionScope {
+        object : AutoTransitionTestAssertionScope {
+            var progress = 0f
+
             override fun onElement(
                 element: ElementKey,
                 scene: SceneKey?,
             ): SemanticsNodeInteraction {
                 return onNode(isElement(element, scene))
             }
+
+            override fun <T> interpolate(from: T, to: T): T {
+                @Suppress("UNCHECKED_CAST")
+                return when {
+                    from is Float && to is Float -> lerp(from, to, progress)
+                    from is Int && to is Int -> lerp(from, to, progress)
+                    from is Long && to is Long -> lerp(from, to, progress)
+                    from is Dp && to is Dp -> lerp(from, to, progress)
+                    else ->
+                        throw UnsupportedOperationException(
+                            "Interpolation not supported for this type"
+                        )
+                }
+                    as T
+            }
         }
 
     lateinit var coroutineScope: CoroutineScope
@@ -321,14 +366,28 @@
     mainClock.advanceTimeByFrame()
     waitForIdle()
 
+    var currentTime = 0L
     // Test the assertions at specific points in time.
     test.timestamps.forEach { tsAssertion ->
         if (tsAssertion.timestampDelta > 0L) {
             mainClock.advanceTimeBy(tsAssertion.timestampDelta)
             waitForIdle()
+            currentTime += tsAssertion.timestampDelta.toInt()
         }
 
-        tsAssertion.assertion(assertionScope)
+        assertionScope.progress = tsAssertion.progress
+        try {
+            tsAssertion.assertion(assertionScope, tsAssertion.progress)
+        } catch (assertionError: AssertionError) {
+            if (assertionScope.progress > 0) {
+                throw AssertionError(
+                    "Transition assertion failed at ${currentTime}ms " +
+                        "at progress: ${assertionScope.progress}f",
+                    assertionError,
+                )
+            }
+            throw assertionError
+        }
     }
 
     // Go to the end state and test it.
@@ -371,7 +430,25 @@
                     val delta = timestamp - currentTimestamp
                     currentTimestamp = timestamp
 
-                    timestamps.add(TimestampAssertion(delta, builder))
+                    timestamps.add(TimestampAssertion(delta, { builder() }, 0f))
+                }
+
+                override fun atAllFrames(
+                    totalFrames: Int,
+                    builder: AutoTransitionTestAssertionScope.(Float) -> Unit,
+                ) {
+                    check(after == null) { "atFrames(...) {} must be called before after {}" }
+                    check(currentTimestamp == 0L) {
+                        "atFrames(...) can't be called multiple times or after at(...)"
+                    }
+
+                    for (frame in 0 until totalFrames) {
+                        val timestamp = frame * 16L
+                        val delta = timestamp - currentTimestamp
+                        val progress = frame.toFloat() / totalFrames
+                        currentTimestamp = timestamp
+                        timestamps.add(TimestampAssertion(delta, builder, progress))
+                    }
                 }
 
                 override fun after(builder: TransitionTestAssertionScope.() -> Unit) {
@@ -396,5 +473,6 @@
 
 private class TimestampAssertion(
     val timestampDelta: Long,
-    val assertion: TransitionTestAssertionScope.() -> Unit,
+    val assertion: AutoTransitionTestAssertionScope.(Float) -> Unit,
+    val progress: Float,
 )
diff --git a/packages/SystemUI/customization/res/values/dimens.xml b/packages/SystemUI/customization/res/values/dimens.xml
index 21b4c71..2bb5541 100644
--- a/packages/SystemUI/customization/res/values/dimens.xml
+++ b/packages/SystemUI/customization/res/values/dimens.xml
@@ -33,6 +33,7 @@
     <dimen name="small_clock_height">114dp</dimen>
     <dimen name="small_clock_padding_top">28dp</dimen>
     <dimen name="clock_padding_start">28dp</dimen>
+    <dimen name="weather_date_icon_padding">28dp</dimen>
 
     <!-- When large clock is showing, offset the smartspace by this amount -->
     <dimen name="keyguard_smartspace_top_offset">12dp</dimen>
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderClient.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderClient.kt
index 34c4dfb..48af2d9 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderClient.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderClient.kt
@@ -25,6 +25,7 @@
 import android.graphics.Color
 import android.graphics.drawable.Drawable
 import android.net.Uri
+import android.os.Bundle
 import android.util.Log
 import androidx.annotation.DrawableRes
 import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
@@ -51,10 +52,7 @@
      * selected affordances on the slot will move the selected affordance to the newest location in
      * the slot.
      */
-    suspend fun insertSelection(
-        slotId: String,
-        affordanceId: String,
-    )
+    suspend fun insertSelection(slotId: String, affordanceId: String)
 
     /** Returns all available slots supported by the device. */
     suspend fun querySlots(): List<Slot>
@@ -63,6 +61,11 @@
     suspend fun queryFlags(): List<Flag>
 
     /**
+     * Returns [Bundle] where the keys are from [CustomizationProviderContract.RuntimeValuesTable]
+     */
+    suspend fun queryRuntimeValues(): Bundle
+
+    /**
      * Returns [Flow] for observing the collection of slots.
      *
      * @see [querySlots]
@@ -77,6 +80,13 @@
     fun observeFlags(): Flow<List<Flag>>
 
     /**
+     * Returns [Flow] for observing the variables from the System UI.
+     *
+     * @see [queryRuntimeValues]
+     */
+    fun observeRuntimeValues(): Flow<Bundle>
+
+    /**
      * Returns all available affordances supported by the device, regardless of current slot
      * placement.
      */
@@ -100,15 +110,10 @@
     fun observeSelections(): Flow<List<Selection>>
 
     /** Unselects an affordance with the given ID from the slot with the given ID. */
-    suspend fun deleteSelection(
-        slotId: String,
-        affordanceId: String,
-    )
+    suspend fun deleteSelection(slotId: String, affordanceId: String)
 
     /** Unselects all affordances from the slot with the given ID. */
-    suspend fun deleteAllSelections(
-        slotId: String,
-    )
+    suspend fun deleteAllSelections(slotId: String)
 
     /** Returns a [Drawable] with the given ID, loaded from the system UI package. */
     suspend fun getAffordanceIcon(
@@ -200,10 +205,7 @@
     private val backgroundDispatcher: CoroutineDispatcher,
 ) : CustomizationProviderClient {
 
-    override suspend fun insertSelection(
-        slotId: String,
-        affordanceId: String,
-    ) {
+    override suspend fun insertSelection(slotId: String, affordanceId: String) {
         withContext(backgroundDispatcher) {
             context.contentResolver.insert(
                 Contract.LockScreenQuickAffordances.SelectionTable.URI,
@@ -211,9 +213,9 @@
                     put(Contract.LockScreenQuickAffordances.SelectionTable.Columns.SLOT_ID, slotId)
                     put(
                         Contract.LockScreenQuickAffordances.SelectionTable.Columns.AFFORDANCE_ID,
-                        affordanceId
+                        affordanceId,
                     )
-                }
+                },
             )
         }
     }
@@ -221,13 +223,7 @@
     override suspend fun querySlots(): List<CustomizationProviderClient.Slot> {
         return withContext(backgroundDispatcher) {
             context.contentResolver
-                .query(
-                    Contract.LockScreenQuickAffordances.SlotTable.URI,
-                    null,
-                    null,
-                    null,
-                    null,
-                )
+                .query(Contract.LockScreenQuickAffordances.SlotTable.URI, null, null, null, null)
                 ?.use { cursor ->
                     buildList {
                         val idColumnIndex =
@@ -252,42 +248,55 @@
                         }
                     }
                 }
-        }
-            ?: emptyList()
+        } ?: emptyList()
     }
 
     override suspend fun queryFlags(): List<CustomizationProviderClient.Flag> {
         return withContext(backgroundDispatcher) {
-            context.contentResolver
-                .query(
-                    Contract.FlagsTable.URI,
-                    null,
-                    null,
-                    null,
-                    null,
-                )
-                ?.use { cursor ->
-                    buildList {
+            context.contentResolver.query(Contract.FlagsTable.URI, null, null, null, null)?.use {
+                cursor ->
+                buildList {
+                    val nameColumnIndex = cursor.getColumnIndex(Contract.FlagsTable.Columns.NAME)
+                    val valueColumnIndex = cursor.getColumnIndex(Contract.FlagsTable.Columns.VALUE)
+                    if (nameColumnIndex == -1 || valueColumnIndex == -1) {
+                        return@buildList
+                    }
+
+                    while (cursor.moveToNext()) {
+                        add(
+                            CustomizationProviderClient.Flag(
+                                name = cursor.getString(nameColumnIndex),
+                                value = cursor.getInt(valueColumnIndex) == 1,
+                            )
+                        )
+                    }
+                }
+            }
+        } ?: emptyList()
+    }
+
+    override suspend fun queryRuntimeValues(): Bundle {
+        return withContext(backgroundDispatcher) {
+            Bundle().apply {
+                context.contentResolver
+                    .query(Contract.RuntimeValuesTable.URI, null, null, null, null)
+                    ?.use { cursor ->
                         val nameColumnIndex =
                             cursor.getColumnIndex(Contract.FlagsTable.Columns.NAME)
                         val valueColumnIndex =
                             cursor.getColumnIndex(Contract.FlagsTable.Columns.VALUE)
-                        if (nameColumnIndex == -1 || valueColumnIndex == -1) {
-                            return@buildList
-                        }
-
-                        while (cursor.moveToNext()) {
-                            add(
-                                CustomizationProviderClient.Flag(
-                                    name = cursor.getString(nameColumnIndex),
-                                    value = cursor.getInt(valueColumnIndex) == 1,
-                                )
-                            )
+                        if (nameColumnIndex >= 0 && valueColumnIndex >= 0) {
+                            while (cursor.moveToNext()) {
+                                when (val name = cursor.getString(nameColumnIndex)) {
+                                    Contract.RuntimeValuesTable.KEY_IS_SHADE_LAYOUT_WIDE -> {
+                                        putBoolean(name, cursor.getInt(valueColumnIndex) == 1)
+                                    }
+                                }
+                            }
                         }
                     }
-                }
+            }
         }
-            ?: emptyList()
     }
 
     override fun observeSlots(): Flow<List<CustomizationProviderClient.Slot>> {
@@ -298,6 +307,10 @@
         return observeUri(Contract.FlagsTable.URI).map { queryFlags() }
     }
 
+    override fun observeRuntimeValues(): Flow<Bundle> {
+        return observeUri(Contract.RuntimeValuesTable.URI).map { queryRuntimeValues() }
+    }
+
     override suspend fun queryAffordances(): List<CustomizationProviderClient.Affordance> {
         return withContext(backgroundDispatcher) {
             context.contentResolver
@@ -375,22 +388,17 @@
                                     enablementActionIntent =
                                         cursor
                                             .getString(enablementActionIntentColumnIndex)
-                                            ?.toIntent(
-                                                affordanceId = affordanceId,
-                                            ),
+                                            ?.toIntent(affordanceId = affordanceId),
                                     configureIntent =
                                         cursor
                                             .getString(configureIntentColumnIndex)
-                                            ?.toIntent(
-                                                affordanceId = affordanceId,
-                                            ),
+                                            ?.toIntent(affordanceId = affordanceId),
                                 )
                             )
                         }
                     }
                 }
-        }
-            ?: emptyList()
+        } ?: emptyList()
     }
 
     override fun observeAffordances(): Flow<List<CustomizationProviderClient.Affordance>> {
@@ -444,8 +452,7 @@
                         }
                     }
                 }
-        }
-            ?: emptyList()
+        } ?: emptyList()
     }
 
     override fun observeSelections(): Flow<List<CustomizationProviderClient.Selection>> {
@@ -454,34 +461,24 @@
         }
     }
 
-    override suspend fun deleteSelection(
-        slotId: String,
-        affordanceId: String,
-    ) {
+    override suspend fun deleteSelection(slotId: String, affordanceId: String) {
         withContext(backgroundDispatcher) {
             context.contentResolver.delete(
                 Contract.LockScreenQuickAffordances.SelectionTable.URI,
                 "${Contract.LockScreenQuickAffordances.SelectionTable.Columns.SLOT_ID} = ? AND" +
                     " ${Contract.LockScreenQuickAffordances.SelectionTable.Columns.AFFORDANCE_ID}" +
                     " = ?",
-                arrayOf(
-                    slotId,
-                    affordanceId,
-                ),
+                arrayOf(slotId, affordanceId),
             )
         }
     }
 
-    override suspend fun deleteAllSelections(
-        slotId: String,
-    ) {
+    override suspend fun deleteAllSelections(slotId: String) {
         withContext(backgroundDispatcher) {
             context.contentResolver.delete(
                 Contract.LockScreenQuickAffordances.SelectionTable.URI,
                 Contract.LockScreenQuickAffordances.SelectionTable.Columns.SLOT_ID,
-                arrayOf(
-                    slotId,
-                ),
+                arrayOf(slotId),
             )
         }
     }
@@ -499,9 +496,7 @@
         }
     }
 
-    private fun observeUri(
-        uri: Uri,
-    ): Flow<Unit> {
+    private fun observeUri(uri: Uri): Flow<Unit> {
         return callbackFlow {
                 val observer =
                     object : ContentObserver(null) {
@@ -522,9 +517,7 @@
             .flowOn(backgroundDispatcher)
     }
 
-    private fun String.toIntent(
-        affordanceId: String,
-    ): Intent? {
+    private fun String.toIntent(affordanceId: String): Intent? {
         return try {
             Intent.parseUri(this, Intent.URI_INTENT_SCHEME)
         } catch (e: URISyntaxException) {
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
index 8721c78..cb167ed 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
@@ -198,4 +198,27 @@
             const val VALUE = "value"
         }
     }
+
+    object RuntimeValuesTable {
+        const val TABLE_NAME = "runtime_values"
+        val URI: Uri = BASE_URI.buildUpon().path(TABLE_NAME).build()
+
+        /**
+         * This key corresponds to an Int value, where `1` means `true` and `0` means `false`.
+         *
+         * Whether the shade layout should be wide (true) or narrow (false).
+         *
+         * In a wide layout, notifications and quick settings each take up only half the screen
+         * width (whether they are shown at the same time or not). In a narrow layout, they can each
+         * be as wide as the entire screen.
+         */
+        const val KEY_IS_SHADE_LAYOUT_WIDE = "is_shade_layout_wide"
+
+        object Columns {
+            /** String. Unique ID for the value. */
+            const val NAME = "name"
+            /** Type depends on the key name. */
+            const val VALUE = "value"
+        }
+    }
 }
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/FakeCustomizationProviderClient.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/FakeCustomizationProviderClient.kt
index f5a955d..47c5bda 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/FakeCustomizationProviderClient.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/FakeCustomizationProviderClient.kt
@@ -19,6 +19,7 @@
 
 import android.graphics.drawable.BitmapDrawable
 import android.graphics.drawable.Drawable
+import android.os.Bundle
 import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -64,11 +65,13 @@
                 value = true,
             )
         ),
+    runtimeValues: Bundle = Bundle(),
 ) : CustomizationProviderClient {
 
     private val slots = MutableStateFlow(slots)
     private val affordances = MutableStateFlow(affordances)
     private val flags = MutableStateFlow(flags)
+    private val runtimeValues = MutableStateFlow(runtimeValues)
 
     private val selections = MutableStateFlow<Map<String, List<String>>>(emptyMap())
 
@@ -93,6 +96,10 @@
         return flags.value
     }
 
+    override suspend fun queryRuntimeValues(): Bundle {
+        return runtimeValues.value
+    }
+
     override fun observeSlots(): Flow<List<CustomizationProviderClient.Slot>> {
         return slots.asStateFlow()
     }
@@ -101,6 +108,10 @@
         return flags.asStateFlow()
     }
 
+    override fun observeRuntimeValues(): Flow<Bundle> {
+        return runtimeValues.asStateFlow()
+    }
+
     override suspend fun queryAffordances(): List<CustomizationProviderClient.Affordance> {
         return affordances.value
     }
@@ -139,10 +150,7 @@
         }
     }
 
-    fun setFlag(
-        name: String,
-        value: Boolean,
-    ) {
+    fun setFlag(name: String, value: Boolean) {
         flags.value =
             flags.value.toMutableList().apply {
                 removeIf { it.name == name }
@@ -150,6 +158,10 @@
             }
     }
 
+    fun setRuntimeValues(runtimeValues: Bundle) {
+        this.runtimeValues.value = runtimeValues
+    }
+
     fun setSlotCapacity(slotId: String, capacity: Int) {
         slots.value =
             slots.value.toMutableList().apply {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefsTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefsTest.java
index 944066fa..d47ec8c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefsTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefsTest.java
@@ -25,15 +25,12 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
-import android.platform.test.annotations.DisableFlags;
-import android.platform.test.annotations.EnableFlags;
 import android.testing.TestableLooper;
 import android.util.Size;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.util.FakeSharedPreferences;
 
@@ -59,18 +56,6 @@
         mWindowMagnificationFrameSizePrefs = new WindowMagnificationFrameSizePrefs(mContext);
     }
 
-    @DisableFlags(Flags.FLAG_SAVE_AND_RESTORE_MAGNIFICATION_SETTINGS_BUTTONS)
-    @Test
-    public void saveSizeForCurrentDensity_getExpectedSize() {
-        Size testSize = new Size(500, 500);
-        mWindowMagnificationFrameSizePrefs
-                .saveIndexAndSizeForCurrentDensity(MagnificationSize.CUSTOM, testSize);
-
-        assertThat(mWindowMagnificationFrameSizePrefs.getSizeForCurrentDensity())
-                .isEqualTo(testSize);
-    }
-
-    @EnableFlags(Flags.FLAG_SAVE_AND_RESTORE_MAGNIFICATION_SETTINGS_BUTTONS)
     @Test
     public void saveSizeForCurrentDensity_validPreference_getExpectedSize() {
         int testIndex = MagnificationSize.MEDIUM;
@@ -81,7 +66,6 @@
                 .isEqualTo(testSize);
     }
 
-    @EnableFlags(Flags.FLAG_SAVE_AND_RESTORE_MAGNIFICATION_SETTINGS_BUTTONS)
     @Test
     public void saveSizeForCurrentDensity_validPreference_getExpectedIndex() {
         int testIndex = MagnificationSize.MEDIUM;
@@ -92,7 +76,6 @@
                 .isEqualTo(testIndex);
     }
 
-    @EnableFlags(Flags.FLAG_SAVE_AND_RESTORE_MAGNIFICATION_SETTINGS_BUTTONS)
     @Test
     public void saveSizeForCurrentDensity_invalidPreference_getDefaultIndex() {
         mSharedPreferences
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/fontscaling b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt
similarity index 91%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/fontscaling
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt
index 0bd00fb..73efea7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/fontscaling
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt
@@ -28,7 +28,6 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.DialogTransitionAnimator
 import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView
-import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView.OnSeekBarWithIconButtonsChangeListener
 import com.android.systemui.model.SysUiState
 import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
@@ -50,8 +49,8 @@
 import org.mockito.Mock
 import org.mockito.Mockito.spy
 import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
 
 private const val ON: Int = 1
 private const val OFF: Int = 0
@@ -103,7 +102,7 @@
                     systemClock,
                     userTracker,
                     mainHandler,
-                    backgroundDelayableExecutor
+                    backgroundDelayableExecutor,
                 )
             )
 
@@ -116,7 +115,7 @@
                 sysuiState,
                 fakeBroadcastDispatcher,
                 mDialogTransitionAnimator,
-                fontScalingDialogDelegate
+                fontScalingDialogDelegate,
             )
 
         whenever(dialogFactory.create(any(), any())).thenReturn(dialog)
@@ -132,7 +131,7 @@
             systemSettings.getFloatForUser(
                 Settings.System.FONT_SCALE,
                 /* def= */ 1.0f,
-                userTracker.userId
+                userTracker.userId,
             )
 
         assertThat(currentScale).isEqualTo(fontSizeValueArray[progress].toFloat())
@@ -163,7 +162,7 @@
             systemSettings.getFloatForUser(
                 Settings.System.FONT_SCALE,
                 /* def= */ 1.0f,
-                userTracker.userId
+                userTracker.userId,
             )
         assertThat(seekBar.getProgress()).isEqualTo(1)
         assertThat(currentScale).isEqualTo(fontSizeValueArray[1].toFloat())
@@ -194,7 +193,7 @@
             systemSettings.getFloatForUser(
                 Settings.System.FONT_SCALE,
                 /* def= */ 1.0f,
-                userTracker.userId
+                userTracker.userId,
             )
         assertThat(seekBar.getProgress()).isEqualTo(fontSizeValueArray.size - 2)
         assertThat(currentScale)
@@ -211,7 +210,7 @@
         secureSettings.putIntForUser(
             Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
             OFF,
-            userTracker.userId
+            userTracker.userId,
         )
 
         // Default seekbar progress for font size is 1, click start icon to decrease the progress
@@ -224,7 +223,7 @@
             secureSettings.getIntForUser(
                 Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
                 /* def = */ OFF,
-                userTracker.userId
+                userTracker.userId,
             )
         assertThat(currentSettings).isEqualTo(ON)
 
@@ -236,13 +235,13 @@
         dialog.show()
 
         val slider = dialog.findViewById<SeekBarWithIconButtonsView>(R.id.font_scaling_slider)!!
-        val changeListener = slider.onSeekBarWithIconButtonsChangeListener
+        val seekBarListener = slider.getSeekBarChangeListener()
 
         val seekBar: SeekBar = slider.findViewById(R.id.seekbar)!!
 
         // Default seekbar progress for font size is 1, simulate dragging to 0 without
         // releasing the finger.
-        changeListener.onStartTrackingTouch(seekBar)
+        seekBarListener.onStartTrackingTouch(seekBar)
         // Update seekbar progress. This will trigger onProgressChanged in the
         // OnSeekBarChangeListener and the seekbar could get updated progress value
         // in onStopTrackingTouch.
@@ -256,21 +255,12 @@
             systemSettings.getFloatForUser(
                 Settings.System.FONT_SCALE,
                 /* def= */ 1.0f,
-                userTracker.userId
+                userTracker.userId,
             )
         assertThat(systemScale).isEqualTo(1.0f)
 
         // Simulate releasing the finger from the seekbar.
-        changeListener.onStopTrackingTouch(seekBar)
-        backgroundDelayableExecutor.runAllReady()
-        backgroundDelayableExecutor.advanceClockToNext()
-        backgroundDelayableExecutor.runAllReady()
-
-        // SeekBar interaction is finalized.
-        changeListener.onUserInteractionFinalized(
-            seekBar,
-            OnSeekBarWithIconButtonsChangeListener.ControlUnitType.SLIDER
-        )
+        seekBarListener.onStopTrackingTouch(seekBar)
         backgroundDelayableExecutor.runAllReady()
         backgroundDelayableExecutor.advanceClockToNext()
         backgroundDelayableExecutor.runAllReady()
@@ -280,7 +270,7 @@
             systemSettings.getFloatForUser(
                 Settings.System.FONT_SCALE,
                 /* def= */ 1.0f,
-                userTracker.userId
+                userTracker.userId,
             )
         assertThat(systemScale).isEqualTo(fontSizeValueArray[0].toFloat())
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/activity/data/repository/ActivityManagerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/activity/data/repository/ActivityManagerRepositoryTest.kt
new file mode 100644
index 0000000..d6ba98d
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/activity/data/repository/ActivityManagerRepositoryTest.kt
@@ -0,0 +1,143 @@
+/*
+ * 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.activity.data.repository
+
+import android.app.ActivityManager
+import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
+import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE
+import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_TOP_SLEEPING
+import android.app.activityManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.log.core.Logger
+import com.android.systemui.log.logcatLogBuffer
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ActivityManagerRepositoryTest : SysuiTestCase() {
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+    private val logger = Logger(logcatLogBuffer("ActivityManagerRepositoryTest"), "tag")
+
+    private val Kosmos.underTest by Kosmos.Fixture { realActivityManagerRepository }
+
+    @Test
+    fun createIsAppVisibleFlow_fetchesInitialValue_true() =
+        kosmos.runTest {
+            whenever(activityManager.getUidImportance(THIS_UID)).thenReturn(IMPORTANCE_FOREGROUND)
+
+            val latest by
+                collectLastValue(underTest.createIsAppVisibleFlow(THIS_UID, logger, LOG_TAG))
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun createIsAppVisibleFlow_fetchesInitialValue_false() =
+        kosmos.runTest {
+            whenever(activityManager.getUidImportance(THIS_UID)).thenReturn(IMPORTANCE_GONE)
+
+            val latest by
+                collectLastValue(underTest.createIsAppVisibleFlow(THIS_UID, logger, LOG_TAG))
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun createIsAppVisibleFlow_getsImportanceUpdates() =
+        kosmos.runTest {
+            val latest by
+                collectLastValue(underTest.createIsAppVisibleFlow(THIS_UID, logger, LOG_TAG))
+
+            val listenerCaptor = argumentCaptor<ActivityManager.OnUidImportanceListener>()
+            verify(activityManager).addOnUidImportanceListener(listenerCaptor.capture(), any())
+            val listener = listenerCaptor.firstValue
+
+            listener.onUidImportance(THIS_UID, IMPORTANCE_GONE)
+            assertThat(latest).isFalse()
+
+            listener.onUidImportance(THIS_UID, IMPORTANCE_FOREGROUND)
+            assertThat(latest).isTrue()
+
+            listener.onUidImportance(THIS_UID, IMPORTANCE_TOP_SLEEPING)
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun createIsAppVisibleFlow_ignoresUpdatesForOtherUids() =
+        kosmos.runTest {
+            val latest by
+                collectLastValue(underTest.createIsAppVisibleFlow(THIS_UID, logger, LOG_TAG))
+
+            val listenerCaptor = argumentCaptor<ActivityManager.OnUidImportanceListener>()
+            verify(activityManager).addOnUidImportanceListener(listenerCaptor.capture(), any())
+            val listener = listenerCaptor.firstValue
+
+            listener.onUidImportance(THIS_UID, IMPORTANCE_GONE)
+            assertThat(latest).isFalse()
+
+            // WHEN another UID becomes foreground
+            listener.onUidImportance(THIS_UID + 2, IMPORTANCE_FOREGROUND)
+
+            // THEN this UID still stays not visible
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun createIsAppVisibleFlow_securityExceptionOnUidRegistration_ok() =
+        kosmos.runTest {
+            whenever(activityManager.getUidImportance(THIS_UID)).thenReturn(IMPORTANCE_GONE)
+            whenever(activityManager.addOnUidImportanceListener(any(), any()))
+                .thenThrow(SecurityException())
+
+            val latest by
+                collectLastValue(underTest.createIsAppVisibleFlow(THIS_UID, logger, LOG_TAG))
+
+            // Verify no crash, and we get a value emitted
+            assertThat(latest).isFalse()
+        }
+
+    /** Regression test for b/216248574. */
+    @Test
+    fun createIsAppVisibleFlow_getUidImportanceThrowsException_ok() =
+        kosmos.runTest {
+            whenever(activityManager.getUidImportance(any())).thenThrow(SecurityException())
+
+            val latest by
+                collectLastValue(underTest.createIsAppVisibleFlow(THIS_UID, logger, LOG_TAG))
+
+            // Verify no crash, and we get a value emitted
+            assertThat(latest).isFalse()
+        }
+
+    companion object {
+        private const val THIS_UID = 558
+        private const val LOG_TAG = "LogTag"
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt
index cdda9cc..41cc6ee 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt
@@ -48,8 +48,8 @@
 import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index 91f9cce..b8d4bb4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -667,6 +667,7 @@
             faceProps,
             wakefulnessLifecycle,
             userManager,
+            null /* authContextPlugins */,
             lockPatternUtils,
             interactionJankMonitor,
             { promptSelectorInteractor },
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 2dcbdc8..2817f55 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -117,6 +117,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 import java.util.Random;
 
 @RunWith(AndroidJUnit4.class)
@@ -1187,7 +1188,8 @@
         TestableAuthController(Context context) {
             super(context, null /* applicationCoroutineScope */,
                     mExecution, mCommandQueue, mActivityTaskManager, mWindowManager,
-                    mFingerprintManager, mFaceManager, () -> mUdfpsController, mDisplayManager,
+                    mFingerprintManager, mFaceManager, Optional.empty(),
+                    () -> mUdfpsController, mDisplayManager,
                     mWakefulnessLifecycle, mUserManager, mLockPatternUtils, () -> mUdfpsLogger,
                     () -> mLogContextInteractor, () -> mPromptSelectionInteractor,
                     () -> mCredentialViewModel, () -> mPromptViewModel, mInteractionJankMonitor,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 21c6583..aeea99b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -365,6 +365,25 @@
     }
 
     @Test
+    public void showUdfpsOverlay_invokedTwice_doesNotNotifyListenerSecondTime() throws RemoteException {
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
+                BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+        mFgExecutor.runAllReady();
+
+        verify(mFingerprintManager).onUdfpsUiEvent(FingerprintManager.UDFPS_UI_OVERLAY_SHOWN,
+                TEST_REQUEST_ID, mOpticalProps.sensorId);
+
+        reset(mFingerprintManager);
+
+        // Second attempt should do nothing
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
+                BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+        mFgExecutor.runAllReady();
+        verify(mFingerprintManager, never()).onUdfpsUiEvent(FingerprintManager.UDFPS_UI_OVERLAY_SHOWN,
+                TEST_REQUEST_ID, mOpticalProps.sensorId);
+    }
+
+    @Test
     public void testSubscribesToOrientationChangesWhenShowingOverlay() throws Exception {
         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
                 BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt
index 25f9565..a11dace 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.bluetooth.qsdialog
 
 import android.bluetooth.BluetoothLeBroadcast
+import android.bluetooth.BluetoothLeBroadcastMetadata
 import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -50,6 +51,7 @@
     @get:Rule val mockito: MockitoRule = MockitoJUnit.rule()
     private val kosmos = testKosmos()
     @Mock private lateinit var localBluetoothLeBroadcast: LocalBluetoothLeBroadcast
+    @Mock private lateinit var bluetoothLeBroadcastMetadata: BluetoothLeBroadcastMetadata
     @Captor private lateinit var callbackCaptor: ArgumentCaptor<BluetoothLeBroadcast.Callback>
     private lateinit var underTest: AudioSharingInteractor
 
@@ -202,7 +204,7 @@
                 verify(localBluetoothLeBroadcast)
                     .registerServiceCallBack(any(), callbackCaptor.capture())
                 runCurrent()
-                callbackCaptor.value.onPlaybackStarted(0, 0)
+                callbackCaptor.value.onBroadcastMetadataChanged(0, bluetoothLeBroadcastMetadata)
                 runCurrent()
 
                 assertThat(bluetoothTileDialogAudioSharingRepository.sourceAdded).isTrue()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/composable b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/composable/BouncerPredictiveBackTest.kt
similarity index 95%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/composable
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/composable/BouncerPredictiveBackTest.kt
index 97f2e56..b33a83c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/composable
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/composable/BouncerPredictiveBackTest.kt
@@ -59,6 +59,7 @@
 import com.android.systemui.lifecycle.ExclusiveActivatable
 import com.android.systemui.lifecycle.rememberViewModel
 import com.android.systemui.motion.createSysUiComposeMotionTestRule
+import com.android.systemui.qs.ui.viewmodel.fakeQsSceneAdapter
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.domain.startable.sceneContainerStartable
 import com.android.systemui.scene.sceneContainerViewModelFactory
@@ -67,6 +68,7 @@
 import com.android.systemui.scene.shared.model.sceneDataSourceDelegator
 import com.android.systemui.scene.ui.composable.Scene
 import com.android.systemui.scene.ui.composable.SceneContainer
+import com.android.systemui.scene.ui.composable.SceneContainerTransitions
 import com.android.systemui.testKosmos
 import kotlin.time.Duration.Companion.seconds
 import kotlinx.coroutines.awaitCancellation
@@ -114,7 +116,13 @@
     private val Kosmos.initialSceneKey by Fixture { Scenes.Bouncer }
     private val Kosmos.sceneContainerConfig by Fixture {
         val navigationDistances = mapOf(Scenes.Lockscreen to 1, Scenes.Bouncer to 0)
-        SceneContainerConfig(sceneKeys, initialSceneKey, emptyList(), navigationDistances)
+        SceneContainerConfig(
+            sceneKeys,
+            initialSceneKey,
+            SceneContainerTransitions,
+            emptyList(),
+            navigationDistances,
+        )
     }
     private val view = mock<View>()
 
@@ -181,8 +189,10 @@
                                         Scenes.Bouncer to bouncerScene,
                                     ),
                                 initialSceneKey = Scenes.Bouncer,
+                                sceneTransitions = SceneContainerTransitions,
                                 overlayByKey = emptyMap(),
                                 dataSourceDelegator = kosmos.sceneDataSourceDelegator,
+                                qsSceneAdapter = { kosmos.fakeQsSceneAdapter },
                             )
                         }
                     },
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModelTest.kt
index 3bf4460..94f6769 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModelTest.kt
@@ -34,6 +34,11 @@
 import com.android.systemui.flags.EnableSceneContainer
 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.shared.model.DismissAction
+import com.android.systemui.keyguard.shared.model.KeyguardDone
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.lifecycle.activateIn
 import com.android.systemui.res.R
@@ -212,6 +217,25 @@
             assertThat(isFoldSplitRequired).isTrue()
         }
 
+    @Test
+    fun onUiDestroyed_clearsPendingDismissAction() =
+        kosmos.runTest {
+            val dismissAction by collectLastValue(fakeKeyguardRepository.dismissAction)
+            fakeKeyguardRepository.setDismissAction(
+                DismissAction.RunImmediately(
+                    onDismissAction = { KeyguardDone.IMMEDIATE },
+                    onCancelAction = {},
+                    message = "",
+                    willAnimateOnLockscreen = true,
+                )
+            )
+            assertThat(dismissAction).isNotEqualTo(DismissAction.None)
+
+            underTest.onUiDestroyed()
+
+            assertThat(dismissAction).isEqualTo(DismissAction.None)
+        }
+
     private fun authMethodsToTest(): List<AuthenticationMethodModel> {
         return listOf(None, Pin, Password, Pattern, Sim)
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt
index 0f148f8..2d093bf 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt
@@ -25,6 +25,7 @@
 import com.android.systemui.brightness.domain.interactor.screenBrightnessInteractor
 import com.android.systemui.brightness.shared.model.GammaBrightness
 import com.android.systemui.brightness.shared.model.LinearBrightness
+import com.android.systemui.classifier.domain.interactor.falsingInteractor
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.common.shared.model.Text
@@ -61,6 +62,7 @@
                 brightnessPolicyEnforcementInteractor,
                 sliderHapticsViewModelFactory,
                 brightnessMirrorShowingInteractor,
+                falsingInteractor,
                 supportsMirroring = true,
                 brightnessWarningToast,
             )
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java
index cecb525..01baadd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java
@@ -19,7 +19,6 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
@@ -129,16 +128,43 @@
     }
 
     @Test
-    public void setProgress_onlyOnProgressChangedTriggeredWithFromUserFalse() {
+    public void setProgress_onProgressChangedAndOnUserInteractionFinalized() {
         reset(mOnSeekBarChangeListener);
         mIconDiscreteSliderLinearLayout.setProgress(1);
 
+        // If users are changing seekbar progress without touching the seekbar or clicking the
+        // buttons, trigger onUserInteractionFinalized.
         verify(mOnSeekBarChangeListener).onProgressChanged(
                 eq(mSeekbar), /* progress= */ eq(1), /* fromUser= */ eq(false));
         verify(mOnSeekBarChangeListener, never()).onStartTrackingTouch(/* seekBar= */ any());
         verify(mOnSeekBarChangeListener, never()).onStopTrackingTouch(/* seekBar= */ any());
+        verify(mOnSeekBarChangeListener).onUserInteractionFinalized(
+                /* seekBar= */ any(),
+                eq(OnSeekBarWithIconButtonsChangeListener.ControlUnitType.SLIDER));
+    }
+
+    @Test
+    public void setProgressToSeekBarByTouch_onUserInteractionFinalizedAfterTouchEnds() {
+        reset(mOnSeekBarChangeListener);
+        final SeekBarWithIconButtonsView.SeekBarChangeListener seekBarChangeListener =
+                mIconDiscreteSliderLinearLayout.getSeekBarChangeListener();
+        final SeekBar seekBar = mIconDiscreteSliderLinearLayout.findViewById(R.id.seekbar);
+
+        // Simulate changing seekbar progress by touch
+        seekBarChangeListener.onStartTrackingTouch(seekBar);
+        mIconDiscreteSliderLinearLayout.setProgress(1);
+
+        verify(mOnSeekBarChangeListener).onProgressChanged(
+                eq(mSeekbar), /* progress= */ eq(1), /* fromUser= */ eq(false));
         verify(mOnSeekBarChangeListener, never()).onUserInteractionFinalized(
-                /* seekBar= */any(), /* control= */ anyInt());
+                /* seekBar= */ any(),
+                eq(OnSeekBarWithIconButtonsChangeListener.ControlUnitType.SLIDER));
+
+        // Notify onUserInteractionFinalized after touch ends
+        seekBarChangeListener.onStopTrackingTouch(seekBar);
+        verify(mOnSeekBarChangeListener).onUserInteractionFinalized(
+                /* seekBar= */ any(),
+                eq(OnSeekBarWithIconButtonsChangeListener.ControlUnitType.SLIDER));
     }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt
index 06b710e..b66727e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt
@@ -22,6 +22,7 @@
 import android.app.admin.devicePolicyManager
 import android.content.Intent
 import android.content.pm.UserInfo
+import android.content.res.mainResources
 import android.os.UserManager.USER_TYPE_PROFILE_MANAGED
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
@@ -29,6 +30,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
+import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.broadcastDispatcher
 import com.android.systemui.communal.data.model.DisabledReason
@@ -53,7 +55,8 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class CommunalSettingsRepositoryImplTest : SysuiTestCase() {
-    private val kosmos = testKosmos()
+    private val kosmos =
+        testKosmos().apply { mainResources = mContext.orCreateTestableResources.resources }
     private val testScope = kosmos.testScope
     private lateinit var underTest: CommunalSettingsRepository
 
@@ -67,6 +70,7 @@
     }
 
     @EnableFlags(FLAG_COMMUNAL_HUB)
+    @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
     @Test
     fun getFlagEnabled_bothEnabled() {
         kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
@@ -74,7 +78,7 @@
         assertThat(underTest.getFlagEnabled()).isTrue()
     }
 
-    @DisableFlags(FLAG_COMMUNAL_HUB)
+    @DisableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2)
     @Test
     fun getFlagEnabled_bothDisabled() {
         kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false)
@@ -82,7 +86,7 @@
         assertThat(underTest.getFlagEnabled()).isFalse()
     }
 
-    @DisableFlags(FLAG_COMMUNAL_HUB)
+    @DisableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2)
     @Test
     fun getFlagEnabled_onlyClassicFlagEnabled() {
         kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
@@ -91,6 +95,7 @@
     }
 
     @EnableFlags(FLAG_COMMUNAL_HUB)
+    @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
     @Test
     fun getFlagEnabled_onlyTrunkFlagEnabled() {
         kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false)
@@ -98,6 +103,57 @@
         assertThat(underTest.getFlagEnabled()).isFalse()
     }
 
+    @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
+    @DisableFlags(FLAG_COMMUNAL_HUB)
+    @Test
+    fun getFlagEnabled_mobileConfigEnabled() {
+        mContext.orCreateTestableResources.addOverride(
+            com.android.internal.R.bool.config_glanceableHubEnabled,
+            true,
+        )
+
+        assertThat(underTest.getFlagEnabled()).isTrue()
+    }
+
+    @DisableFlags(FLAG_GLANCEABLE_HUB_V2, FLAG_COMMUNAL_HUB)
+    @Test
+    fun getFlagEnabled_onlyMobileConfigEnabled() {
+        mContext.orCreateTestableResources.addOverride(
+            com.android.internal.R.bool.config_glanceableHubEnabled,
+            true,
+        )
+
+        assertThat(underTest.getFlagEnabled()).isFalse()
+    }
+
+    @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
+    @DisableFlags(FLAG_COMMUNAL_HUB)
+    @Test
+    fun getFlagEnabled_onlyMobileFlagEnabled() {
+        mContext.orCreateTestableResources.addOverride(
+            com.android.internal.R.bool.config_glanceableHubEnabled,
+            false,
+        )
+
+        assertThat(underTest.getFlagEnabled()).isFalse()
+    }
+
+    @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
+    @DisableFlags(FLAG_COMMUNAL_HUB)
+    @Test
+    fun getFlagEnabled_oldFlagIgnored() {
+        // New config flag enabled.
+        mContext.orCreateTestableResources.addOverride(
+            com.android.internal.R.bool.config_glanceableHubEnabled,
+            true,
+        )
+
+        // Old config flag disabled.
+        kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false)
+
+        assertThat(underTest.getFlagEnabled()).isTrue()
+    }
+
     @EnableFlags(FLAG_COMMUNAL_HUB)
     @Test
     fun secondaryUserIsInvalid() =
@@ -134,7 +190,7 @@
             kosmos.fakeSettings.putIntForUser(
                 Settings.Secure.GLANCEABLE_HUB_ENABLED,
                 0,
-                PRIMARY_USER.id
+                PRIMARY_USER.id,
             )
             val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER))
             assertThat(enabledState?.enabled).isFalse()
@@ -143,14 +199,14 @@
             kosmos.fakeSettings.putIntForUser(
                 Settings.Secure.GLANCEABLE_HUB_ENABLED,
                 1,
-                SECONDARY_USER.id
+                SECONDARY_USER.id,
             )
             assertThat(enabledState?.enabled).isFalse()
 
             kosmos.fakeSettings.putIntForUser(
                 Settings.Secure.GLANCEABLE_HUB_ENABLED,
                 1,
-                PRIMARY_USER.id
+                PRIMARY_USER.id,
             )
             assertThat(enabledState?.enabled).isTrue()
         }
@@ -201,7 +257,7 @@
             kosmos.fakeSettings.putIntForUser(
                 Settings.Secure.GLANCEABLE_HUB_ENABLED,
                 0,
-                PRIMARY_USER.id
+                PRIMARY_USER.id,
             )
             setKeyguardFeaturesDisabled(PRIMARY_USER, KEYGUARD_DISABLE_WIDGETS_ALL)
 
@@ -228,7 +284,7 @@
                 kosmos.fakeSettings.putIntForUser(
                     GLANCEABLE_HUB_BACKGROUND_SETTING,
                     type.value,
-                    PRIMARY_USER.id
+                    PRIMARY_USER.id,
                 )
                 assertWithMessage(
                         "Expected $type when $GLANCEABLE_HUB_BACKGROUND_SETTING is set to" +
@@ -253,12 +309,6 @@
             UserInfo(/* id= */ 0, /* name= */ "primary user", /* flags= */ UserInfo.FLAG_MAIN)
         val SECONDARY_USER = UserInfo(/* id= */ 1, /* name= */ "secondary user", /* flags= */ 0)
         val WORK_PROFILE =
-            UserInfo(
-                10,
-                "work",
-                /* iconPath= */ "",
-                /* flags= */ 0,
-                USER_TYPE_PROFILE_MANAGED,
-            )
+            UserInfo(10, "work", /* iconPath= */ "", /* flags= */ 0, USER_TYPE_PROFILE_MANAGED)
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
index 5bbd3ff..18cc8bf 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
@@ -172,16 +172,16 @@
         }
 
     @Test
-    fun selectedKey_onReorderWidgets_isCleared() =
+    fun selectedKey_onReorderWidgets_isSet() =
         testScope.runTest {
             val selectedKey by collectLastValue(underTest.selectedKey)
 
-            val key = CommunalContentModel.KEY.widget(123)
-            underTest.setSelectedKey(key)
-            assertThat(selectedKey).isEqualTo(key)
-
-            underTest.onReorderWidgetStart()
+            underTest.setSelectedKey(null)
             assertThat(selectedKey).isNull()
+
+            val key = CommunalContentModel.KEY.widget(123)
+            underTest.onReorderWidgetStart(key)
+            assertThat(selectedKey).isEqualTo(key)
         }
 
     @Test
@@ -234,7 +234,7 @@
 
     @Test
     fun reorderWidget_uiEventLogging_start() {
-        underTest.onReorderWidgetStart()
+        underTest.onReorderWidgetStart(CommunalContentModel.KEY.widget(123))
         verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_START)
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
index d90d58b..1bb5c9a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
@@ -43,7 +43,6 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
 import com.android.systemui.kosmos.testScope
-import com.android.systemui.scene.domain.interactor.sceneBackInteractor
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.domain.startable.sceneContainerStartable
 import com.android.systemui.scene.shared.model.Scenes
@@ -72,7 +71,6 @@
     private val trustRepository by lazy { kosmos.fakeTrustRepository }
     private val sceneInteractor by lazy { kosmos.sceneInteractor }
     private val authenticationInteractor by lazy { kosmos.authenticationInteractor }
-    private val sceneBackInteractor by lazy { kosmos.sceneBackInteractor }
     private val sceneContainerStartable by lazy { kosmos.sceneContainerStartable }
     private val sysuiStatusBarStateController by lazy { kosmos.sysuiStatusBarStateController }
     private lateinit var underTest: DeviceEntryInteractor
@@ -437,7 +435,9 @@
     fun isDeviceEntered_unlockedWhileOnShade_emitsTrue() =
         testScope.runTest {
             val isDeviceEntered by collectLastValue(underTest.isDeviceEntered)
+            val isDeviceEnteredDirectly by collectLastValue(underTest.isDeviceEnteredDirectly)
             assertThat(isDeviceEntered).isFalse()
+            assertThat(isDeviceEnteredDirectly).isFalse()
             val currentScene by collectLastValue(sceneInteractor.currentScene)
             assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
 
@@ -445,19 +445,20 @@
             switchToScene(Scenes.Shade)
             assertThat(currentScene).isEqualTo(Scenes.Shade)
             // Simulating a "leave it open when the keyguard is hidden" which means the bouncer will
-            // be
-            // shown and successful authentication should take the user back to where they are, the
-            // shade scene.
+            // be shown and successful authentication should take the user back to where they are,
+            // the shade scene.
             sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(true)
             switchToScene(Scenes.Bouncer)
             assertThat(currentScene).isEqualTo(Scenes.Bouncer)
 
             assertThat(isDeviceEntered).isFalse()
+            assertThat(isDeviceEnteredDirectly).isFalse()
             // Authenticate with PIN to unlock and dismiss the lockscreen:
             authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)
             runCurrent()
 
             assertThat(isDeviceEntered).isTrue()
+            assertThat(isDeviceEnteredDirectly).isFalse()
         }
 
     private fun TestScope.switchToScene(sceneKey: SceneKey) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/domain/interactor/DisplayWindowPropertiesInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/domain/interactor/DisplayWindowPropertiesInteractorImplTest.kt
new file mode 100644
index 0000000..e1344ca
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/domain/interactor/DisplayWindowPropertiesInteractorImplTest.kt
@@ -0,0 +1,61 @@
+/*
+ * 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.display.domain.interactor
+
+import android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
+import android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR
+import android.view.layoutInflater
+import android.view.windowManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.display.data.repository.fakeDisplayWindowPropertiesRepository
+import com.android.systemui.display.shared.model.DisplayWindowProperties
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class DisplayWindowPropertiesInteractorImplTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+    private val repo = kosmos.fakeDisplayWindowPropertiesRepository
+
+    private val underTest = kosmos.displayWindowPropertiesInteractor
+
+    @Test
+    fun getForStatusBar_returnsPropertiesWithCorrectWindowType() {
+        val displayId = 123
+        val statusBarWindowProperties = createDisplayWindowProperties(displayId, TYPE_STATUS_BAR)
+        val navBarWindowProperties = createDisplayWindowProperties(displayId, TYPE_NAVIGATION_BAR)
+        repo.insert(statusBarWindowProperties)
+        repo.insert(navBarWindowProperties)
+
+        assertThat(underTest.getForStatusBar(displayId)).isEqualTo(statusBarWindowProperties)
+    }
+
+    private fun createDisplayWindowProperties(displayId: Int, windowType: Int) =
+        DisplayWindowProperties(
+            displayId,
+            windowType,
+            context,
+            kosmos.windowManager,
+            kosmos.layoutInflater,
+        )
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeScreenStateTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeScreenStateTest.java
index ba578a3..bbd78b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeScreenStateTest.java
@@ -35,7 +35,7 @@
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Matchers.anyObject;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.verify;
@@ -315,6 +315,6 @@
     public void authCallbackRemovedOnDestroy() {
         mScreen.destroy();
 
-        verify(mAuthController).removeCallback(anyObject());
+        verify(mAuthController).removeCallback(any());
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
index bbfc960..a804879 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
@@ -36,7 +36,6 @@
 import androidx.lifecycle.LifecycleOwner
 import androidx.lifecycle.LifecycleRegistry
 import androidx.test.filters.SmallTest
-import com.android.app.viewcapture.ViewCapture
 import com.android.app.viewcapture.ViewCaptureAwareWindowManager
 import com.android.app.viewcapture.ViewCaptureFactory
 import com.android.compose.animation.scene.ObservableTransitionState
@@ -44,15 +43,15 @@
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
 import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
+import com.android.systemui.Flags.FLAG_COMMUNAL_HUB_ON_MOBILE
 import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.ambient.touch.TouchHandler
 import com.android.systemui.ambient.touch.TouchMonitor
 import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent
 import com.android.systemui.ambient.touch.scrim.ScrimController
 import com.android.systemui.ambient.touch.scrim.ScrimManager
-import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
-import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository
 import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.communal.domain.interactor.communalInteractor
@@ -64,6 +63,7 @@
 import com.android.systemui.complication.dagger.ComplicationComponent
 import com.android.systemui.dreams.complication.HideComplicationTouchHandler
 import com.android.systemui.dreams.dagger.DreamOverlayComponent
+import com.android.systemui.dreams.touch.CommunalTouchHandler
 import com.android.systemui.flags.andSceneContainer
 import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
 import com.android.systemui.keyguard.gesture.domain.gestureInteractor
@@ -87,21 +87,17 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
-import org.mockito.Captor
-import org.mockito.Mock
 import org.mockito.Mockito
 import org.mockito.Mockito.clearInvocations
 import org.mockito.Mockito.isNull
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
 import org.mockito.kotlin.any
 import org.mockito.kotlin.argumentCaptor
 import org.mockito.kotlin.eq
 import org.mockito.kotlin.firstValue
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.spy
-import org.mockito.kotlin.times
 import org.mockito.kotlin.verifyNoMoreInteractions
 import org.mockito.kotlin.whenever
 import platform.test.runner.parameterized.ParameterizedAndroidJunit4
@@ -117,68 +113,50 @@
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
 
-    @Mock lateinit var mLifecycleOwner: DreamOverlayLifecycleOwner
+    private val mLifecycleOwner = mock<DreamOverlayLifecycleOwner>()
+    private val mDreamOverlayCallback = mock<IDreamOverlayCallback>()
+    private val mWindowManager = mock<WindowManagerImpl>()
+    private val mComplicationComponentFactory = mock<ComplicationComponent.Factory>()
+    private val mComplicationHostViewController = mock<ComplicationHostViewController>()
+    private val mComplicationVisibilityController = mock<ComplicationLayoutEngine>()
+    private val mDreamComplicationComponentFactory =
+        mock<com.android.systemui.dreams.complication.dagger.ComplicationComponent.Factory>()
+    private val mHideComplicationTouchHandler = mock<HideComplicationTouchHandler>()
+    private val mDreamOverlayComponentFactory = mock<DreamOverlayComponent.Factory>()
+    private val mCommunalTouchHandler = mock<CommunalTouchHandler>()
+    private val mAmbientTouchComponentFactory = mock<AmbientTouchComponent.Factory>()
+    private val mDreamOverlayContainerView = mock<DreamOverlayContainerView>()
+    private val mDreamOverlayContainerViewController =
+        mock<DreamOverlayContainerViewController> {
+            on { containerView }.thenReturn(mDreamOverlayContainerView)
+        }
+    private val mKeyguardUpdateMonitor = mock<KeyguardUpdateMonitor>()
+    private val mTouchMonitor = mock<TouchMonitor>()
+    private val mStateController = mock<DreamOverlayStateController>()
+    private val mDreamOverlayContainerViewParent = mock<ViewGroup>()
+    private val mTouchInsetManager = mock<TouchInsetManager>()
+    private val mUiEventLogger = mock<UiEventLogger>()
+    private val mScrimController = mock<ScrimController>()
+    private val mScrimManager =
+        mock<ScrimManager> { on { currentController }.thenReturn(mScrimController) }
+    private val mSystemDialogsCloser = mock<SystemDialogsCloser>()
+    private val mDreamOverlayCallbackController = mock<DreamOverlayCallbackController>()
+    private val mLazyViewCapture = lazy { viewCaptureSpy }
 
-    private lateinit var lifecycleRegistry: FakeLifecycleRegistry
+    private val mViewCaptor = argumentCaptor<View>()
+    private val mTouchHandlersCaptor = argumentCaptor<Set<TouchHandler>>()
 
-    lateinit var mCommunalInteractor: CommunalInteractor
-
-    private lateinit var mWindowParams: WindowManager.LayoutParams
-
-    @Mock lateinit var mDreamOverlayCallback: IDreamOverlayCallback
-
-    @Mock lateinit var mWindowManager: WindowManagerImpl
-
-    @Mock lateinit var mComplicationComponentFactory: ComplicationComponent.Factory
-
-    @Mock lateinit var mComplicationHostViewController: ComplicationHostViewController
-
-    @Mock lateinit var mComplicationVisibilityController: ComplicationLayoutEngine
-
-    @Mock
-    lateinit var mDreamComplicationComponentFactory:
-        com.android.systemui.dreams.complication.dagger.ComplicationComponent.Factory
-
-    @Mock lateinit var mHideComplicationTouchHandler: HideComplicationTouchHandler
-
-    @Mock lateinit var mDreamOverlayComponentFactory: DreamOverlayComponent.Factory
-
-    @Mock lateinit var mAmbientTouchComponentFactory: AmbientTouchComponent.Factory
-
-    @Mock lateinit var mDreamOverlayContainerView: DreamOverlayContainerView
-
-    @Mock lateinit var mDreamOverlayContainerViewController: DreamOverlayContainerViewController
-
-    @Mock lateinit var mKeyguardUpdateMonitor: KeyguardUpdateMonitor
-
-    @Mock lateinit var mTouchMonitor: TouchMonitor
-
-    @Mock lateinit var mStateController: DreamOverlayStateController
-
-    @Mock lateinit var mDreamOverlayContainerViewParent: ViewGroup
-
-    @Mock lateinit var mTouchInsetManager: TouchInsetManager
-
-    @Mock lateinit var mUiEventLogger: UiEventLogger
-
-    @Mock lateinit var mScrimManager: ScrimManager
-
-    @Mock lateinit var mScrimController: ScrimController
-
-    @Mock lateinit var mSystemDialogsCloser: SystemDialogsCloser
-
-    @Mock lateinit var mDreamOverlayCallbackController: DreamOverlayCallbackController
-
-    @Mock lateinit var mLazyViewCapture: Lazy<ViewCapture>
-
-    private lateinit var mViewCaptureAwareWindowManager: ViewCaptureAwareWindowManager
-    private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
-    private lateinit var communalRepository: FakeCommunalSceneRepository
+    private val mWindowParams = WindowManager.LayoutParams()
+    private val lifecycleRegistry = FakeLifecycleRegistry(mLifecycleOwner)
+    private val bouncerRepository = kosmos.fakeKeyguardBouncerRepository
+    private val communalRepository = kosmos.fakeCommunalSceneRepository
     private var viewCaptureSpy = spy(ViewCaptureFactory.getInstance(context))
-    private lateinit var gestureInteractor: GestureInteractor
+    private val gestureInteractor = spy(kosmos.gestureInteractor)
+
+    private lateinit var mCommunalInteractor: CommunalInteractor
+    private lateinit var mViewCaptureAwareWindowManager: ViewCaptureAwareWindowManager
     private lateinit var environmentComponents: EnvironmentComponents
 
-    @Captor var mViewCaptor: ArgumentCaptor<View>? = null
     private lateinit var mService: DreamOverlayService
 
     private class EnvironmentComponents(
@@ -234,6 +212,7 @@
             mock<com.android.systemui.dreams.complication.dagger.ComplicationComponent>()
         whenever(dreamComplicationComponent.getHideComplicationTouchHandler())
             .thenReturn(mHideComplicationTouchHandler)
+        whenever(dreamOverlayComponent.communalTouchHandler).thenReturn(mCommunalTouchHandler)
         whenever(dreamComplicationComponentFactory.create(any(), any()))
             .thenReturn(dreamComplicationComponent)
 
@@ -259,13 +238,6 @@
 
     @Before
     fun setup() {
-        MockitoAnnotations.initMocks(this)
-
-        lifecycleRegistry = FakeLifecycleRegistry(mLifecycleOwner)
-        bouncerRepository = kosmos.fakeKeyguardBouncerRepository
-        communalRepository = kosmos.fakeCommunalSceneRepository
-        gestureInteractor = spy(kosmos.gestureInteractor)
-
         environmentComponents =
             setupComponentFactories(
                 mDreamComplicationComponentFactory,
@@ -273,12 +245,6 @@
                 mComplicationComponentFactory,
                 mAmbientTouchComponentFactory,
             )
-
-        whenever(mDreamOverlayContainerViewController.containerView)
-            .thenReturn(mDreamOverlayContainerView)
-        whenever(mScrimManager.getCurrentController()).thenReturn(mScrimController)
-        whenever(mLazyViewCapture.value).thenReturn(viewCaptureSpy)
-        mWindowParams = WindowManager.LayoutParams()
         mViewCaptureAwareWindowManager =
             ViewCaptureAwareWindowManager(
                 mWindowManager,
@@ -381,10 +347,10 @@
         verify(mStateController).setOverlayActive(false)
         verify(mStateController).setLowLightActive(false)
         verify(mStateController).setEntryAnimationsFinished(false)
-        verify(mStateController, Mockito.never()).setOverlayActive(true)
-        verify(mUiEventLogger, Mockito.never())
+        verify(mStateController, never()).setOverlayActive(true)
+        verify(mUiEventLogger, never())
             .log(DreamOverlayService.DreamOverlayEvent.DREAM_OVERLAY_COMPLETE_START)
-        verify(mDreamOverlayCallbackController, Mockito.never()).onStartDream()
+        verify(mDreamOverlayCallbackController, never()).onStartDream()
     }
 
     @Test
@@ -528,14 +494,14 @@
         mMainExecutor.runAllReady()
 
         // Verify view added.
-        verify(mWindowManager).addView(mViewCaptor!!.capture(), any())
+        verify(mWindowManager).addView(mViewCaptor.capture(), any())
 
         // Service destroyed.
         mService.onEndDream()
         mMainExecutor.runAllReady()
 
         // Verify view removed.
-        verify(mWindowManager).removeView(mViewCaptor!!.value)
+        verify(mWindowManager).removeView(mViewCaptor.firstValue)
 
         // Verify state correctly set.
         verify(mStateController).setOverlayActive(false)
@@ -567,8 +533,8 @@
 
         // The overlay starts then finishes.
         val inOrder = Mockito.inOrder(mWindowManager)
-        inOrder.verify(mWindowManager).addView(mViewCaptor!!.capture(), any())
-        inOrder.verify(mWindowManager).removeView(mViewCaptor!!.value)
+        inOrder.verify(mWindowManager).addView(mViewCaptor.capture(), any())
+        inOrder.verify(mWindowManager).removeView(mViewCaptor.firstValue)
     }
 
     @Test
@@ -596,8 +562,8 @@
 
         // The overlay starts then finishes.
         val inOrder = Mockito.inOrder(mWindowManager)
-        inOrder.verify(mWindowManager).addView(mViewCaptor!!.capture(), any())
-        inOrder.verify(mWindowManager).removeView(mViewCaptor!!.value)
+        inOrder.verify(mWindowManager).addView(mViewCaptor.capture(), any())
+        inOrder.verify(mWindowManager).removeView(mViewCaptor.firstValue)
     }
 
     @Test
@@ -615,14 +581,14 @@
         mMainExecutor.runAllReady()
 
         // Verify view added.
-        verify(mWindowManager).addView(mViewCaptor!!.capture(), any())
+        verify(mWindowManager).addView(mViewCaptor.capture(), any())
 
         // Service destroyed.
         mService.onDestroy()
         mMainExecutor.runAllReady()
 
         // Verify view removed.
-        verify(mWindowManager).removeView(mViewCaptor!!.value)
+        verify(mWindowManager).removeView(mViewCaptor.firstValue)
 
         // Verify state correctly set.
         verify(mKeyguardUpdateMonitor).removeCallback(any())
@@ -639,7 +605,7 @@
         mMainExecutor.runAllReady()
 
         // Verify no view is removed.
-        verify(mWindowManager, Mockito.never()).removeView(any())
+        verify(mWindowManager, never()).removeView(any())
 
         // Verify state still correctly set.
         verify(mKeyguardUpdateMonitor).removeCallback(any())
@@ -665,7 +631,7 @@
             false, /*shouldShowComplication*/
         )
         mMainExecutor.runAllReady()
-        verify(mWindowManager, Mockito.never()).addView(any(), any())
+        verify(mWindowManager, never()).addView(any(), any())
     }
 
     @Test
@@ -673,7 +639,7 @@
         // Service destroyed before dream started.
         mService.onDestroy()
         mMainExecutor.runAllReady()
-        verify(mWindowManager, Mockito.never()).removeView(any())
+        verify(mWindowManager, never()).removeView(any())
     }
 
     @Test
@@ -691,8 +657,8 @@
         mMainExecutor.runAllReady()
 
         // Verify that a new window is added.
-        verify(mWindowManager).addView(mViewCaptor!!.capture(), any())
-        val windowDecorView = mViewCaptor!!.value
+        verify(mWindowManager).addView(mViewCaptor.capture(), any())
+        val windowDecorView = mViewCaptor.firstValue
 
         // Assert that the overlay is not showing complications.
         assertThat(mService.shouldShowComplications()).isFalse()
@@ -751,7 +717,7 @@
     @Test
     fun testWakeUpBeforeStartDoesNothing() {
         mService.onWakeUp()
-        verify(mDreamOverlayContainerViewController, Mockito.never()).onWakeUp()
+        verify(mDreamOverlayContainerViewController, never()).onWakeUp()
     }
 
     @Test
@@ -879,8 +845,8 @@
         )
         mMainExecutor.runAllReady()
 
-        whenever(mDreamOverlayContainerViewController.isBouncerShowing()).thenReturn(true)
-        mService!!.onComeToFront()
+        whenever(mDreamOverlayContainerViewController.isBouncerShowing).thenReturn(true)
+        mService.onComeToFront()
         verify(mScrimController).expand(any())
     }
 
@@ -900,7 +866,7 @@
         )
         mMainExecutor.runAllReady()
 
-        mService!!.onComeToFront()
+        mService.onComeToFront()
         assertThat(communalRepository.currentScene.value).isEqualTo(CommunalScenes.Blank)
     }
 
@@ -920,7 +886,7 @@
         )
         mMainExecutor.runAllReady()
 
-        mService!!.onComeToFront()
+        mService.onComeToFront()
         verify(mSystemDialogsCloser).closeSystemDialogs()
     }
 
@@ -1320,6 +1286,45 @@
         environmentComponents.verifyNoMoreInteractions()
     }
 
+    @DisableFlags(FLAG_COMMUNAL_HUB_ON_MOBILE)
+    @Test
+    fun testAmbientTouchHandlersRegistration_registerHideComplicationAndCommunal() {
+        val client = client
+
+        // Inform the overlay service of dream starting.
+        client.startDream(
+            mWindowParams,
+            mDreamOverlayCallback,
+            DREAM_COMPONENT,
+            false /*isPreview*/,
+            false, /*shouldShowComplication*/
+        )
+        mMainExecutor.runAllReady()
+
+        verify(mAmbientTouchComponentFactory).create(any(), mTouchHandlersCaptor.capture(), any())
+        assertThat(mTouchHandlersCaptor.firstValue)
+            .containsExactly(mHideComplicationTouchHandler, mCommunalTouchHandler)
+    }
+
+    @EnableFlags(FLAG_COMMUNAL_HUB_ON_MOBILE)
+    @Test
+    fun testAmbientTouchHandlersRegistration_v2_registerOnlyHideComplication() {
+        val client = client
+
+        // Inform the overlay service of dream starting.
+        client.startDream(
+            mWindowParams,
+            mDreamOverlayCallback,
+            DREAM_COMPONENT,
+            false /*isPreview*/,
+            false, /*shouldShowComplication*/
+        )
+        mMainExecutor.runAllReady()
+
+        verify(mAmbientTouchComponentFactory).create(any(), mTouchHandlersCaptor.capture(), any())
+        assertThat(mTouchHandlersCaptor.firstValue).containsExactly(mHideComplicationTouchHandler)
+    }
+
     internal class FakeLifecycleRegistry(provider: LifecycleOwner) : LifecycleRegistry(provider) {
         val mLifecycles: MutableList<State> = ArrayList()
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt
index 82bcece..55b87db 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
 import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.communal.domain.interactor.setCommunalAvailable
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
 import com.android.systemui.flags.EnableSceneContainer
@@ -72,8 +73,10 @@
 
     @Test
     @DisableFlags(DualShade.FLAG_NAME)
-    fun actions_singleShade() =
+    fun actions_communalNotAvailable_singleShade() =
         testScope.runTest {
+            kosmos.setCommunalAvailable(false)
+
             val actions by collectLastValue(underTest.actions)
 
             setUpState(
@@ -85,6 +88,8 @@
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
             assertThat(actions?.get(Swipe.Down))
                 .isEqualTo(UserActionResult(Scenes.Shade, isIrreversible = true))
+            assertThat(actions?.get(Swipe.Start)).isNull()
+            assertThat(actions?.get(Swipe.End)).isNull()
 
             setUpState(
                 isShadeTouchable = false,
@@ -102,12 +107,16 @@
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
             assertThat(actions?.get(Swipe.Down))
                 .isEqualTo(UserActionResult(Scenes.Shade, isIrreversible = true))
+            assertThat(actions?.get(Swipe.Start)).isNull()
+            assertThat(actions?.get(Swipe.End)).isNull()
         }
 
     @Test
     @DisableFlags(DualShade.FLAG_NAME)
-    fun actions_splitShade() =
+    fun actions_communalNotAvailable_splitShade() =
         testScope.runTest {
+            kosmos.setCommunalAvailable(false)
+
             val actions by collectLastValue(underTest.actions)
 
             setUpState(
@@ -119,6 +128,8 @@
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
             assertThat(actions?.get(Swipe.Down))
                 .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade, isIrreversible = true))
+            assertThat(actions?.get(Swipe.Start)).isNull()
+            assertThat(actions?.get(Swipe.End)).isNull()
 
             setUpState(
                 isShadeTouchable = false,
@@ -136,12 +147,16 @@
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
             assertThat(actions?.get(Swipe.Down))
                 .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade, isIrreversible = true))
+            assertThat(actions?.get(Swipe.Start)).isNull()
+            assertThat(actions?.get(Swipe.End)).isNull()
         }
 
     @Test
     @EnableFlags(DualShade.FLAG_NAME)
-    fun actions_dualShade() =
+    fun actions_communalNotAvailable_dualShade() =
         testScope.runTest {
+            kosmos.setCommunalAvailable(false)
+
             val actions by collectLastValue(underTest.actions)
 
             setUpState(
@@ -155,6 +170,8 @@
                 .isEqualTo(
                     UserActionResult.ShowOverlay(Overlays.NotificationsShade, isIrreversible = true)
                 )
+            assertThat(actions?.get(Swipe.Start)).isNull()
+            assertThat(actions?.get(Swipe.End)).isNull()
 
             setUpState(
                 isShadeTouchable = false,
@@ -170,6 +187,128 @@
                 .isEqualTo(
                     UserActionResult.ShowOverlay(Overlays.NotificationsShade, isIrreversible = true)
                 )
+            assertThat(actions?.get(Swipe.Start)).isNull()
+            assertThat(actions?.get(Swipe.End)).isNull()
+        }
+
+    @Test
+    @DisableFlags(DualShade.FLAG_NAME)
+    fun actions_communalAvailable_singleShade() =
+        testScope.runTest {
+            kosmos.setCommunalAvailable(true)
+
+            val actions by collectLastValue(underTest.actions)
+
+            setUpState(
+                isShadeTouchable = true,
+                isDeviceUnlocked = false,
+                shadeMode = ShadeMode.Single,
+            )
+            assertThat(actions).isNotEmpty()
+            assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
+            assertThat(actions?.get(Swipe.Down))
+                .isEqualTo(UserActionResult(Scenes.Shade, isIrreversible = true))
+            assertThat(actions?.get(Swipe.Start)).isEqualTo(UserActionResult(Scenes.Communal))
+            assertThat(actions?.get(Swipe.End)).isNull()
+
+            setUpState(
+                isShadeTouchable = false,
+                isDeviceUnlocked = false,
+                shadeMode = ShadeMode.Single,
+            )
+            assertThat(actions).isEmpty()
+
+            setUpState(
+                isShadeTouchable = true,
+                isDeviceUnlocked = true,
+                shadeMode = ShadeMode.Single,
+            )
+            assertThat(actions).isNotEmpty()
+            assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
+            assertThat(actions?.get(Swipe.Down))
+                .isEqualTo(UserActionResult(Scenes.Shade, isIrreversible = true))
+            assertThat(actions?.get(Swipe.Start)).isEqualTo(UserActionResult(Scenes.Communal))
+            assertThat(actions?.get(Swipe.End)).isNull()
+        }
+
+    @Test
+    @DisableFlags(DualShade.FLAG_NAME)
+    fun actions_communalAvailable_splitShade() =
+        testScope.runTest {
+            kosmos.setCommunalAvailable(true)
+
+            val actions by collectLastValue(underTest.actions)
+
+            setUpState(
+                isShadeTouchable = true,
+                isDeviceUnlocked = false,
+                shadeMode = ShadeMode.Split,
+            )
+            assertThat(actions).isNotEmpty()
+            assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
+            assertThat(actions?.get(Swipe.Down))
+                .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade, isIrreversible = true))
+            assertThat(actions?.get(Swipe.Start)).isEqualTo(UserActionResult(Scenes.Communal))
+            assertThat(actions?.get(Swipe.End)).isNull()
+
+            setUpState(
+                isShadeTouchable = false,
+                isDeviceUnlocked = false,
+                shadeMode = ShadeMode.Split,
+            )
+            assertThat(actions).isEmpty()
+
+            setUpState(
+                isShadeTouchable = true,
+                isDeviceUnlocked = true,
+                shadeMode = ShadeMode.Split,
+            )
+            assertThat(actions).isNotEmpty()
+            assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
+            assertThat(actions?.get(Swipe.Down))
+                .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade, isIrreversible = true))
+            assertThat(actions?.get(Swipe.Start)).isEqualTo(UserActionResult(Scenes.Communal))
+            assertThat(actions?.get(Swipe.End)).isNull()
+        }
+
+    @Test
+    @EnableFlags(DualShade.FLAG_NAME)
+    fun actions_communalAvailable_dualShade() =
+        testScope.runTest {
+            kosmos.setCommunalAvailable(true)
+
+            val actions by collectLastValue(underTest.actions)
+
+            setUpState(
+                isShadeTouchable = true,
+                isDeviceUnlocked = false,
+                shadeMode = ShadeMode.Dual,
+            )
+            assertThat(actions).isNotEmpty()
+            assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
+            assertThat(actions?.get(Swipe.Down))
+                .isEqualTo(
+                    UserActionResult.ShowOverlay(Overlays.NotificationsShade, isIrreversible = true)
+                )
+            assertThat(actions?.get(Swipe.Start)).isEqualTo(UserActionResult(Scenes.Communal))
+            assertThat(actions?.get(Swipe.End)).isNull()
+
+            setUpState(
+                isShadeTouchable = false,
+                isDeviceUnlocked = false,
+                shadeMode = ShadeMode.Dual,
+            )
+            assertThat(actions).isEmpty()
+
+            setUpState(isShadeTouchable = true, isDeviceUnlocked = true, shadeMode = ShadeMode.Dual)
+            assertThat(actions).isNotEmpty()
+            assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
+            assertThat(actions?.get(Swipe.Down))
+                .isEqualTo(
+                    UserActionResult.ShowOverlay(Overlays.NotificationsShade, isIrreversible = true)
+                )
+            assertThat(actions?.get(Swipe.Start)).isEqualTo(UserActionResult(Scenes.Communal))
+            assertThat(actions?.get(Swipe.End)).isNull()
         }
 
     private fun TestScope.setUpState(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt
index dd83702..e288522 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt
@@ -25,6 +25,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.contextualeducation.GestureType
 import com.android.systemui.contextualeducation.GestureType.BACK
+import com.android.systemui.contextualeducation.GestureType.HOME
 import com.android.systemui.education.data.repository.fakeEduClock
 import com.android.systemui.education.domain.interactor.KeyboardTouchpadEduInteractor
 import com.android.systemui.education.domain.interactor.contextualEducationInteractor
@@ -52,6 +53,7 @@
 import org.mockito.Mock
 import org.mockito.junit.MockitoJUnit
 import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
 
@@ -66,6 +68,7 @@
     private val minDurationForNextEdu =
         KeyboardTouchpadEduInteractor.minIntervalBetweenEdu + 1.seconds
     private lateinit var underTest: ContextualEduUiCoordinator
+    private lateinit var previousDialog: Dialog
     @Mock private lateinit var dialog: Dialog
     @Mock private lateinit var notificationManager: NotificationManager
     @Mock private lateinit var accessibilityManagerWrapper: AccessibilityManagerWrapper
@@ -95,9 +98,11 @@
                 kosmos.applicationCoroutineScope,
                 viewModel,
                 kosmos.applicationContext,
-                notificationManager
+                notificationManager,
             ) { model ->
                 toastContent = model.message
+                previousDialog = dialog
+                dialog = mock<Dialog>()
                 dialog
             }
         underTest.start()
@@ -129,6 +134,14 @@
         }
 
     @Test
+    fun dismissPreviousDialogOnNewDialog() =
+        testScope.runTest {
+            triggerEducation(BACK)
+            triggerEducation(HOME)
+            verify(previousDialog).dismiss()
+        }
+
+    @Test
     fun verifyBackEduToastContent() =
         testScope.runTest {
             triggerEducation(BACK)
@@ -149,14 +162,14 @@
             verifyNotificationContent(
                 R.string.back_edu_notification_title,
                 R.string.back_edu_notification_content,
-                notificationCaptor.value
+                notificationCaptor.value,
             )
         }
 
     private fun verifyNotificationContent(
         titleResId: Int,
         contentResId: Int,
-        notification: Notification
+        notification: Notification,
     ) {
         val expectedContent = context.getString(contentResId)
         val expectedTitle = context.getString(titleResId)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt
index 639737b..76434ee 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt
@@ -27,9 +27,11 @@
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger
 import com.android.systemui.inputdevice.tutorial.domain.interactor.KeyboardTouchpadConnectionInteractor
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_KEY
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_KEYBOARD
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_TOUCHPAD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_KEY
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_KEYBOARD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_TOUCHPAD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_TOUCHPAD_BACK
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_TOUCHPAD_HOME
 import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.ACTION_KEY
 import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.BACK_GESTURE
 import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.HOME_GESTURE
@@ -66,8 +68,8 @@
     private val sysUiState = kosmos.sysUiState
     private val touchpadRepo = PrettyFakeTouchpadRepository()
     private val keyboardRepo = kosmos.keyboardRepository
-    private var startingPeripheral = INTENT_TUTORIAL_TYPE_TOUCHPAD
-    private val viewModel by lazy { createViewModel(startingPeripheral) }
+    private var tutorialScope = INTENT_TUTORIAL_SCOPE_TOUCHPAD
+    private val viewModel by lazy { createViewModel(tutorialScope) }
 
     // createUnsafe so its methods don't have to be called on Main thread
     private val lifecycle = LifecycleRegistry.createUnsafe(mock(LifecycleOwner::class.java))
@@ -75,7 +77,7 @@
     @get:Rule val mainDispatcherRule = MainDispatcherRule(kosmos.testDispatcher)
 
     private fun createViewModel(
-        startingPeripheral: String = INTENT_TUTORIAL_TYPE_TOUCHPAD,
+        scope: String = INTENT_TUTORIAL_SCOPE_TOUCHPAD,
         hasTouchpadTutorialScreens: Boolean = true,
     ): KeyboardTouchpadTutorialViewModel {
         val viewModel =
@@ -84,7 +86,7 @@
                 KeyboardTouchpadConnectionInteractor(keyboardRepo, touchpadRepo),
                 hasTouchpadTutorialScreens,
                 mock<InputDeviceTutorialLogger>(),
-                SavedStateHandle(mapOf(INTENT_TUTORIAL_TYPE_KEY to startingPeripheral))
+                SavedStateHandle(mapOf(INTENT_TUTORIAL_SCOPE_KEY to scope)),
             )
         lifecycle.addObserver(viewModel)
         return viewModel
@@ -169,7 +171,7 @@
     @Test
     fun screensOrder_whenGoingBackAndOnlyKeyboardConnected() =
         testScope.runTest {
-            startingPeripheral = INTENT_TUTORIAL_TYPE_KEYBOARD
+            tutorialScope = INTENT_TUTORIAL_SCOPE_KEYBOARD
             val screens by collectValues(viewModel.screen)
             val closeActivity by collectLastValue(viewModel.closeActivity)
             peripheralsState(keyboardConnected = true, touchpadConnected = false)
@@ -185,7 +187,7 @@
     @Test
     fun screensOrder_whenTouchpadConnected() =
         testScope.runTest {
-            startingPeripheral = INTENT_TUTORIAL_TYPE_TOUCHPAD
+            tutorialScope = INTENT_TUTORIAL_SCOPE_TOUCHPAD
             val screens by collectValues(viewModel.screen)
             val closeActivity by collectLastValue(viewModel.closeActivity)
 
@@ -193,22 +195,47 @@
 
             goToNextScreen()
             goToNextScreen()
-            goToNextScreen()
 
             assertThat(screens).containsExactly(BACK_GESTURE, HOME_GESTURE).inOrder()
             assertThat(closeActivity).isTrue()
         }
 
     @Test
-    fun screensOrder_whenKeyboardConnected() =
+    fun screensOrder_withBackGestureScope() =
         testScope.runTest {
-            startingPeripheral = INTENT_TUTORIAL_TYPE_KEYBOARD
+            tutorialScope = INTENT_TUTORIAL_SCOPE_TOUCHPAD_BACK
             val screens by collectValues(viewModel.screen)
             val closeActivity by collectLastValue(viewModel.closeActivity)
-
-            peripheralsState(keyboardConnected = true)
+            peripheralsState(touchpadConnected = true)
 
             goToNextScreen()
+
+            assertThat(screens).containsExactly(BACK_GESTURE).inOrder()
+            assertThat(closeActivity).isTrue()
+        }
+
+    @Test
+    fun screensOrder_withHomeGestureScope() =
+        testScope.runTest {
+            tutorialScope = INTENT_TUTORIAL_SCOPE_TOUCHPAD_HOME
+            val screens by collectValues(viewModel.screen)
+            val closeActivity by collectLastValue(viewModel.closeActivity)
+            peripheralsState(touchpadConnected = true)
+
+            goToNextScreen()
+
+            assertThat(screens).containsExactly(HOME_GESTURE).inOrder()
+            assertThat(closeActivity).isTrue()
+        }
+
+    @Test
+    fun screensOrder_withKeyboardScope() =
+        testScope.runTest {
+            tutorialScope = INTENT_TUTORIAL_SCOPE_KEYBOARD
+            val screens by collectValues(viewModel.screen)
+            val closeActivity by collectLastValue(viewModel.closeActivity)
+            peripheralsState(keyboardConnected = true)
+
             goToNextScreen()
 
             assertThat(screens).containsExactly(ACTION_KEY).inOrder()
@@ -218,7 +245,7 @@
     @Test
     fun touchpadGesturesDisabled_onlyDuringTouchpadTutorial() =
         testScope.runTest {
-            startingPeripheral = INTENT_TUTORIAL_TYPE_TOUCHPAD
+            tutorialScope = INTENT_TUTORIAL_SCOPE_TOUCHPAD
             collectValues(viewModel.screen) // just to initialize viewModel
             peripheralsState(keyboardConnected = true, touchpadConnected = true)
 
@@ -234,8 +261,8 @@
         testScope.runTest {
             val viewModel =
                 createViewModel(
-                    startingPeripheral = INTENT_TUTORIAL_TYPE_TOUCHPAD,
-                    hasTouchpadTutorialScreens = false
+                    scope = INTENT_TUTORIAL_SCOPE_TOUCHPAD,
+                    hasTouchpadTutorialScreens = false,
                 )
             val screens by collectValues(viewModel.screen)
             val closeActivity by collectLastValue(viewModel.closeActivity)
@@ -248,7 +275,7 @@
     @Test
     fun touchpadGesturesDisabled_whenTutorialGoesToForeground() =
         testScope.runTest {
-            startingPeripheral = INTENT_TUTORIAL_TYPE_TOUCHPAD
+            tutorialScope = INTENT_TUTORIAL_SCOPE_TOUCHPAD
             collectValues(viewModel.screen) // just to initialize viewModel
             peripheralsState(touchpadConnected = true)
 
@@ -260,7 +287,7 @@
     @Test
     fun touchpadGesturesNotDisabled_whenTutorialGoesToBackground() =
         testScope.runTest {
-            startingPeripheral = INTENT_TUTORIAL_TYPE_TOUCHPAD
+            tutorialScope = INTENT_TUTORIAL_SCOPE_TOUCHPAD
             collectValues(viewModel.screen)
             peripheralsState(touchpadConnected = true)
 
@@ -288,7 +315,7 @@
 
     private fun TestScope.peripheralsState(
         keyboardConnected: Boolean = false,
-        touchpadConnected: Boolean = false
+        touchpadConnected: Boolean = false,
     ) {
         keyboardRepo.setIsAnyKeyboardConnected(keyboardConnected)
         touchpadRepo.setIsAnyTouchpadConnected(touchpadConnected)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepositoryTest.kt
index 27b8c59..0d32b7f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepositoryTest.kt
@@ -18,27 +18,30 @@
 
 import android.content.Context
 import android.content.Context.INPUT_SERVICE
+import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_SUCCESS
 import android.hardware.input.fakeInputManager
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import android.view.KeyEvent.KEYCODE_SLASH
-import android.view.KeyEvent.META_ALT_ON
 import android.view.KeyEvent.META_CAPS_LOCK_ON
-import android.view.KeyEvent.META_CTRL_ON
-import android.view.KeyEvent.META_FUNCTION_ON
 import android.view.KeyEvent.META_META_ON
-import android.view.KeyEvent.META_SHIFT_ON
-import android.view.KeyEvent.META_SYM_ON
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.hardware.input.Flags.FLAG_ENABLE_CUSTOMIZABLE_INPUT_GESTURES
 import com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyboard.shared.model.ShortcutCustomizationRequestResult
 import com.android.systemui.keyboard.shortcut.customShortcutCategoriesRepository
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.ALL_SUPPORTED_MODIFIERS
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.allAppsInputGestureData
 import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.allCustomizableInputGesturesWithSimpleShortcutCombinations
 import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.customizableInputGestureWithUnknownKeyGestureType
 import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.expectedShortcutCategoriesWithSimpleShortcutCombination
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.goHomeInputGestureData
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.standardAddCustomShortcutRequestInfo
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.standardDeleteCustomShortcutRequestInfo
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.standardKeyCombination
 import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
 import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
@@ -66,24 +69,21 @@
             it.userTracker = FakeUserTracker(onCreateCurrentUserContext = { mockUserContext })
         }
 
-    private val fakeInputManager = kosmos.fakeInputManager
+    private val inputManager = kosmos.fakeInputManager.inputManager
     private val testScope = kosmos.testScope
     private val helper = kosmos.shortcutHelperTestHelper
     private val repo = kosmos.customShortcutCategoriesRepository
 
     @Before
     fun setup() {
-        whenever(mockUserContext.getSystemService(INPUT_SERVICE))
-            .thenReturn(fakeInputManager.inputManager)
+        whenever(mockUserContext.getSystemService(INPUT_SERVICE)).thenReturn(inputManager)
     }
 
     @Test
     @EnableFlags(FLAG_ENABLE_CUSTOMIZABLE_INPUT_GESTURES, FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
     fun categories_emitsCorrectlyConvertedShortcutCategories() {
         testScope.runTest {
-            whenever(
-                    fakeInputManager.inputManager.getCustomInputGestures(/* filter= */ anyOrNull())
-                )
+            whenever(inputManager.getCustomInputGestures(/* filter= */ anyOrNull()))
                 .thenReturn(allCustomizableInputGesturesWithSimpleShortcutCombinations)
 
             helper.toggle(deviceId = 123)
@@ -98,9 +98,7 @@
     @DisableFlags(FLAG_ENABLE_CUSTOMIZABLE_INPUT_GESTURES, FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
     fun categories_emitsEmptyListWhenFlagIsDisabled() {
         testScope.runTest {
-            whenever(
-                    fakeInputManager.inputManager.getCustomInputGestures(/* filter= */ anyOrNull())
-                )
+            whenever(inputManager.getCustomInputGestures(/* filter= */ anyOrNull()))
                 .thenReturn(allCustomizableInputGesturesWithSimpleShortcutCombinations)
 
             helper.toggle(deviceId = 123)
@@ -114,9 +112,7 @@
     @EnableFlags(FLAG_ENABLE_CUSTOMIZABLE_INPUT_GESTURES, FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
     fun categories_ignoresUnknownKeyGestureTypes() {
         testScope.runTest {
-            whenever(
-                    fakeInputManager.inputManager.getCustomInputGestures(/* filter= */ anyOrNull())
-                )
+            whenever(inputManager.getCustomInputGestures(/* filter= */ anyOrNull()))
                 .thenReturn(customizableInputGestureWithUnknownKeyGestureType)
 
             helper.toggle(deviceId = 123)
@@ -143,7 +139,7 @@
             helper.toggle(deviceId = 123)
             val pressedKeys by collectLastValue(repo.pressedKeys)
             repo.updateUserKeyCombination(
-                KeyCombination(modifiers = allSupportedModifiers, keyCode = null)
+                KeyCombination(modifiers = ALL_SUPPORTED_MODIFIERS, keyCode = null)
             )
 
             assertThat(pressedKeys)
@@ -188,11 +184,71 @@
         }
     }
 
-    private val allSupportedModifiers =
-        META_META_ON or
-            META_CTRL_ON or
-            META_FUNCTION_ON or
-            META_SHIFT_ON or
-            META_ALT_ON or
-            META_SYM_ON
+    @Test
+    fun shortcutBeingCustomized_updatedOnCustomizationRequested() {
+        testScope.runTest {
+            repo.onCustomizationRequested(standardAddCustomShortcutRequestInfo)
+
+            val shortcutBeingCustomized = repo.getShortcutBeingCustomized()
+
+            assertThat(shortcutBeingCustomized).isEqualTo(standardAddCustomShortcutRequestInfo)
+        }
+    }
+
+    @Test
+    fun buildInputGestureDataForShortcutBeingCustomized_noShortcutBeingCustomized_returnsNull() {
+        testScope.runTest {
+            helper.toggle(deviceId = 123)
+            repo.updateUserKeyCombination(standardKeyCombination)
+
+            val inputGestureData = repo.buildInputGestureDataForShortcutBeingCustomized()
+
+            assertThat(inputGestureData).isNull()
+        }
+    }
+
+    @Test
+    fun buildInputGestureDataForShortcutBeingCustomized_noKeyCombinationSelected_returnsNull() {
+        testScope.runTest {
+            helper.toggle(deviceId = 123)
+            repo.onCustomizationRequested(standardAddCustomShortcutRequestInfo)
+
+            val inputGestureData = repo.buildInputGestureDataForShortcutBeingCustomized()
+
+            assertThat(inputGestureData).isNull()
+        }
+    }
+
+    @Test
+    fun buildInputGestureDataForShortcutBeingCustomized_successfullyBuildInputGestureData() {
+        testScope.runTest {
+            helper.toggle(deviceId = 123)
+            repo.onCustomizationRequested(standardAddCustomShortcutRequestInfo)
+            repo.updateUserKeyCombination(standardKeyCombination)
+            val inputGestureData = repo.buildInputGestureDataForShortcutBeingCustomized()
+
+            // using toString as we're testing for only structural equality not referential.
+            // inputGestureData is a java class and isEqual Tests for referential equality
+            // as well which would cause this assert to fail
+            assertThat(inputGestureData.toString()).isEqualTo(allAppsInputGestureData.toString())
+        }
+    }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_CUSTOMIZABLE_INPUT_GESTURES, FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
+    fun deleteShortcut_successfullyRetrievesGestureDataAndDeletesShortcut() {
+        testScope.runTest {
+            whenever(inputManager.getCustomInputGestures(anyOrNull()))
+                .thenReturn(listOf(allAppsInputGestureData, goHomeInputGestureData))
+            whenever(inputManager.removeCustomInputGesture(allAppsInputGestureData))
+                .thenReturn(CUSTOM_INPUT_GESTURE_RESULT_SUCCESS)
+
+            helper.toggle(deviceId = 123)
+            repo.onCustomizationRequested(standardDeleteCustomShortcutRequestInfo)
+
+            val result = repo.deleteShortcutCurrentlyBeingCustomized()
+
+            assertThat(result).isEqualTo(ShortcutCustomizationRequestResult.SUCCESS)
+        }
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSourceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSourceTest.kt
index 715d907..c9f7035 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSourceTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSourceTest.kt
@@ -17,21 +17,28 @@
 package com.android.systemui.keyboard.shortcut.data.source
 
 import android.content.res.mainResources
+import android.hardware.input.KeyGlyphMap
+import android.hardware.input.fakeInputManager
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.view.KeyEvent.KEYCODE_EMOJI_PICKER
 import android.view.KeyboardShortcutGroup
 import android.view.WindowManager.KeyboardShortcutsReceiver
 import android.view.mockWindowManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_SHORTCUT_HELPER_KEY_GLYPH
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+import org.mockito.kotlin.whenever
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
@@ -41,7 +48,8 @@
     private val testScope = kosmos.testScope
 
     private val mockWindowManager = kosmos.mockWindowManager
-    private val source = InputShortcutsSource(kosmos.mainResources, mockWindowManager)
+    private val inputManager = kosmos.fakeInputManager.inputManager
+    private val source = InputShortcutsSource(kosmos.mainResources, mockWindowManager, inputManager)
 
     private var wmImeShortcutGroups: List<KeyboardShortcutGroup>? = null
 
@@ -88,6 +96,36 @@
             assertThat(groups).hasSize(4)
         }
 
+    @Test
+    @EnableFlags(FLAG_SHORTCUT_HELPER_KEY_GLYPH)
+    fun shortcutGroups_flagEnabled_inputManagerReturnsKeyGlyph_returnsEmojiShortcut() =
+        testScope.runTest {
+            val mockKeyGlyph = mock(KeyGlyphMap::class.java)
+            whenever(mockKeyGlyph.functionRowKeys).thenReturn(intArrayOf(KEYCODE_EMOJI_PICKER))
+            whenever(inputManager.getKeyGlyphMap(TEST_DEVICE_ID)).thenReturn(mockKeyGlyph)
+            wmImeShortcutGroups = null
+
+            val groups = source.shortcutGroups(TEST_DEVICE_ID)
+
+            val keyCodes = groups[0].items.map { it.keycode }
+            assertThat(keyCodes).contains(KEYCODE_EMOJI_PICKER)
+        }
+
+    @Test
+    @DisableFlags(FLAG_SHORTCUT_HELPER_KEY_GLYPH)
+    fun shortcutGroups_flagDisabled_inputManagerReturnsKeyGlyph_returnsNoEmojiShortcut() =
+        testScope.runTest {
+            val mockKeyGlyph = mock(KeyGlyphMap::class.java)
+            whenever(mockKeyGlyph.functionRowKeys).thenReturn(intArrayOf(KEYCODE_EMOJI_PICKER))
+            whenever(inputManager.getKeyGlyphMap(TEST_DEVICE_ID)).thenReturn(mockKeyGlyph)
+            wmImeShortcutGroups = null
+
+            val groups = source.shortcutGroups(TEST_DEVICE_ID)
+
+            val keyCodes = groups[0].items.map { it.keycode }
+            assertThat(keyCodes).doesNotContain(KEYCODE_EMOJI_PICKER)
+        }
+
     companion object {
         private const val TEST_DEVICE_ID = 1234
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSourceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSourceTest.kt
new file mode 100644
index 0000000..495e98d
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSourceTest.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright 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.keyboard.shortcut.data.source
+
+import android.content.res.mainResources
+import android.hardware.input.KeyGlyphMap
+import android.hardware.input.KeyGlyphMap.KeyCombination
+import android.hardware.input.fakeInputManager
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.view.KeyEvent
+import android.view.KeyEvent.KEYCODE_BACK
+import android.view.KeyEvent.KEYCODE_HOME
+import android.view.KeyEvent.KEYCODE_RECENT_APPS
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_SHORTCUT_HELPER_KEY_GLYPH
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SystemShortcutsSourceTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+
+    private val inputManager = kosmos.fakeInputManager.inputManager
+    private val source = SystemShortcutsSource(kosmos.mainResources, inputManager)
+    private val mockKeyGlyphMap = mock(KeyGlyphMap::class.java)
+    private val functionRowKeyCodes = listOf(KEYCODE_HOME, KEYCODE_BACK, KEYCODE_RECENT_APPS)
+
+    @Before
+    fun setUp() {
+        whenever(mockKeyGlyphMap.functionRowKeys).thenReturn(intArrayOf())
+        whenever(inputManager.getKeyGlyphMap(TEST_DEVICE_ID)).thenReturn(mockKeyGlyphMap)
+    }
+
+    @Test
+    @EnableFlags(FLAG_SHORTCUT_HELPER_KEY_GLYPH)
+    fun shortcutGroups_flagEnabled_inputManagerReturnsNoFunctionRowKeys_returnsNoFunctionRowShortcuts() =
+        testScope.runTest {
+            val groups = source.shortcutGroups(TEST_DEVICE_ID)
+
+            val keyCodes = groups[0].items.map { it.keycode }
+            assertThat(keyCodes).containsNoneIn(functionRowKeyCodes)
+        }
+
+    @Test
+    @EnableFlags(FLAG_SHORTCUT_HELPER_KEY_GLYPH)
+    fun shortcutGroups_flagEnabled_inputManagerReturnsFunctionRowKeys_returnsFunctionRowShortcuts() =
+        testScope.runTest {
+            whenever(mockKeyGlyphMap.functionRowKeys)
+                .thenReturn(intArrayOf(KEYCODE_HOME, KEYCODE_BACK, KEYCODE_RECENT_APPS))
+
+            val groups = source.shortcutGroups(TEST_DEVICE_ID)
+
+            val keyCodes = groups[0].items.map { it.keycode }
+            assertThat(keyCodes).containsAtLeastElementsIn(functionRowKeyCodes)
+        }
+
+    @Test
+    @DisableFlags(FLAG_SHORTCUT_HELPER_KEY_GLYPH)
+    fun shortcutGroups_flagDisabled_inputManagerReturnsNoFunctionRowKeys_returnsDefaultFunctionRowShortcuts() =
+        testScope.runTest {
+            val groups = source.shortcutGroups(TEST_DEVICE_ID)
+
+            val keyCodes = groups[0].items.map { it.keycode }
+            assertThat(keyCodes).containsAtLeastElementsIn(functionRowKeyCodes)
+        }
+
+    @Test
+    @EnableFlags(FLAG_SHORTCUT_HELPER_KEY_GLYPH)
+    fun shortcutGroups_flagEnabled_inputManagerReturnsHardwareShortcuts_returnsHardwareShortcuts() =
+        testScope.runTest {
+            whenever(mockKeyGlyphMap.functionRowKeys).thenReturn(intArrayOf())
+            val hardwareShortcutMap =
+                mapOf(Pair(KeyCombination(KeyEvent.META_META_ON, KeyEvent.KEYCODE_1), KEYCODE_BACK))
+            whenever(mockKeyGlyphMap.hardwareShortcuts).thenReturn(hardwareShortcutMap)
+
+            val groups = source.shortcutGroups(TEST_DEVICE_ID)
+
+            val shortcuts = groups[0].items.map { c -> Triple(c.label, c.modifiers, c.keycode) }
+            val hardwareShortcut =
+                Triple(
+                    context.getString(R.string.group_system_go_back),
+                    KeyEvent.META_META_ON,
+                    KeyEvent.KEYCODE_1,
+                )
+            assertThat(shortcuts).contains(hardwareShortcut)
+        }
+
+    @Test
+    @DisableFlags(FLAG_SHORTCUT_HELPER_KEY_GLYPH)
+    fun shortcutGroups_flagDisabled_inputManagerReturnsHardwareShortcuts_returnsNoHardwareShortcuts() =
+        testScope.runTest {
+            val hardwareShortcutMap =
+                mapOf(Pair(KeyCombination(KeyEvent.META_META_ON, KeyEvent.KEYCODE_1), KEYCODE_BACK))
+            whenever(mockKeyGlyphMap.hardwareShortcuts).thenReturn(hardwareShortcutMap)
+
+            val groups = source.shortcutGroups(TEST_DEVICE_ID)
+
+            val shortcuts = groups[0].items.map { c -> Triple(c.label, c.modifiers, c.keycode) }
+            val hardwareShortcut =
+                Triple(
+                    context.getString(R.string.group_system_go_back),
+                    KeyEvent.META_META_ON,
+                    KeyEvent.KEYCODE_1,
+                )
+            assertThat(shortcuts).doesNotContain(hardwareShortcut)
+        }
+
+    companion object {
+        private const val TEST_DEVICE_ID = 1234
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
index a1e7ef4..6d22b49 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
@@ -19,9 +19,23 @@
 import android.hardware.input.InputGestureData
 import android.hardware.input.InputGestureData.createKeyTrigger
 import android.hardware.input.KeyGestureEvent
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS
+import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_HOME
+import android.os.SystemClock
 import android.view.KeyEvent
+import android.view.KeyEvent.ACTION_DOWN
+import android.view.KeyEvent.KEYCODE_A
+import android.view.KeyEvent.META_ALT_ON
+import android.view.KeyEvent.META_CTRL_ON
+import android.view.KeyEvent.META_FUNCTION_ON
+import android.view.KeyEvent.META_META_LEFT_ON
+import android.view.KeyEvent.META_META_ON
+import android.view.KeyEvent.META_SHIFT_ON
+import android.view.KeyEvent.META_SHIFT_RIGHT_ON
+import android.view.KeyEvent.META_SYM_ON
 import android.view.KeyboardShortcutGroup
 import android.view.KeyboardShortcutInfo
+import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination
 import com.android.systemui.keyboard.shortcut.shared.model.Shortcut
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
@@ -29,9 +43,11 @@
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MultiTasking
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.System
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
 import com.android.systemui.keyboard.shortcut.shared.model.shortcut
+import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState
 import com.android.systemui.res.R
 
 object TestShortcuts {
@@ -71,6 +87,10 @@
                 key("Shift")
                 key("M")
             }
+            contentDescription {
+                "${shortcutInfoWithRepeatedLabel.label}, " +
+                    "Press key Meta plus H, or Meta plus L, or Shift plus M"
+            }
         }
 
     private val goHomeShortcutInfo =
@@ -93,6 +113,7 @@
                 key(R.drawable.ic_ksh_key_meta)
                 key("N")
             }
+            contentDescription { "${standardShortcutInfo1.label}, Press key Meta plus N" }
         }
 
     private val customGoHomeShortcut =
@@ -103,6 +124,7 @@
                 key("A")
                 isCustom(true)
             }
+            contentDescription { "Go to home screen, Press key Ctrl plus Alt plus A" }
         }
 
     private val standardShortcutInfo2 =
@@ -119,6 +141,7 @@
                 key("Shift")
                 key("Z")
             }
+            contentDescription { "${standardShortcutInfo2.label}, Press key Alt plus Shift plus Z" }
         }
 
     private val standardShortcutInfo3 =
@@ -134,6 +157,7 @@
                 key("Ctrl")
                 key("J")
             }
+            contentDescription { "${standardShortcutInfo3.label}, Press key Ctrl plus J" }
         }
 
     private val shortcutInfoWithUnsupportedModifiers =
@@ -189,6 +213,7 @@
                 key("Ctrl")
                 key("Space")
             }
+            contentDescription { "Switch to next language, Press key Ctrl plus Space" }
         }
 
     private val switchToPreviousLanguageShortcut =
@@ -198,6 +223,9 @@
                 key("Shift")
                 key("Space")
             }
+            contentDescription {
+                "Switch to previous language, Press key Ctrl plus Shift plus Space"
+            }
         }
 
     private val subCategoryForInputLanguageSwitchShortcuts =
@@ -276,6 +304,10 @@
                             key("A")
                             isCustom(true)
                         }
+                        contentDescription {
+                            "Go to home screen, Press key Ctrl plus Alt plus B, " +
+                                "or Ctrl plus Alt plus A"
+                        }
                     }
                 ),
         )
@@ -525,4 +557,110 @@
                 keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER
             ),
         )
+
+    val standardAddCustomShortcutRequestInfo =
+        ShortcutCustomizationRequestInfo.Add(
+            label = "Open apps list",
+            categoryType = System,
+            subCategoryLabel = "System controls",
+        )
+
+    val standardDeleteCustomShortcutRequestInfo =
+        ShortcutCustomizationRequestInfo.Delete(
+            label = "Open apps list",
+            categoryType = System,
+            subCategoryLabel = "System controls",
+        )
+
+    val standardKeyCombination =
+        KeyCombination(
+            modifiers = META_META_ON or META_SHIFT_ON or META_META_LEFT_ON or META_SHIFT_RIGHT_ON,
+            keyCode = KEYCODE_A,
+        )
+
+    const val ALL_SUPPORTED_MODIFIERS =
+        META_META_ON or
+            META_CTRL_ON or
+            META_FUNCTION_ON or
+            META_SHIFT_ON or
+            META_ALT_ON or
+            META_SYM_ON
+
+    val allAppsInputGestureData: InputGestureData =
+        InputGestureData.Builder()
+            .setKeyGestureType(KEY_GESTURE_TYPE_ALL_APPS)
+            .setTrigger(
+                createKeyTrigger(
+                    /* keycode = */ standardKeyCombination.keyCode!!,
+                    /* modifierState = */ standardKeyCombination.modifiers and
+                        ALL_SUPPORTED_MODIFIERS,
+                )
+            )
+            .build()
+
+    val goHomeInputGestureData: InputGestureData =
+        InputGestureData.Builder()
+            .setKeyGestureType(KEY_GESTURE_TYPE_HOME)
+            .setTrigger(
+                createKeyTrigger(
+                    /* keycode = */ standardKeyCombination.keyCode!!,
+                    /* modifierState = */ standardKeyCombination.modifiers and
+                        ALL_SUPPORTED_MODIFIERS,
+                )
+            )
+            .build()
+
+    val expectedStandardDeleteShortcutUiState =
+        ShortcutCustomizationUiState.DeleteShortcutDialog(isDialogShowing = false)
+
+    val keyDownEventWithoutActionKeyPressed =
+        androidx.compose.ui.input.key.KeyEvent(
+            android.view.KeyEvent(
+                /* downTime = */ SystemClock.uptimeMillis(),
+                /* eventTime = */ SystemClock.uptimeMillis(),
+                /* action = */ ACTION_DOWN,
+                /* code = */ KEYCODE_A,
+                /* repeat = */ 0,
+                /* metaState = */ META_CTRL_ON,
+            )
+        )
+
+    val keyDownEventWithActionKeyPressed =
+        androidx.compose.ui.input.key.KeyEvent(
+            android.view.KeyEvent(
+                /* downTime = */ SystemClock.uptimeMillis(),
+                /* eventTime = */ SystemClock.uptimeMillis(),
+                /* action = */ ACTION_DOWN,
+                /* code = */ KEYCODE_A,
+                /* repeat = */ 0,
+                /* metaState = */ META_CTRL_ON or META_META_ON,
+            )
+        )
+
+    val keyUpEventWithActionKeyPressed =
+        androidx.compose.ui.input.key.KeyEvent(
+            android.view.KeyEvent(
+                /* downTime = */ SystemClock.uptimeMillis(),
+                /* eventTime = */ SystemClock.uptimeMillis(),
+                /* action = */ ACTION_DOWN,
+                /* code = */ KEYCODE_A,
+                /* repeat = */ 0,
+                /* metaState = */ 0,
+            )
+        )
+
+    val standardAddShortcutRequest =
+        ShortcutCustomizationRequestInfo.Add(
+            label = "Standard shortcut",
+            categoryType = ShortcutCategoryType.System,
+            subCategoryLabel = "Standard subcategory",
+        )
+
+    val expectedStandardAddShortcutUiState =
+        ShortcutCustomizationUiState.AddShortcutDialog(
+            shortcutLabel = "Standard shortcut",
+            defaultCustomShortcutModifierKey =
+                ShortcutKey.Icon.ResIdIcon(R.drawable.ic_ksh_key_meta),
+            isDialogShowing = false,
+        )
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
index f7c7701..c3cedba 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
@@ -333,6 +333,42 @@
         }
     }
 
+    @Test
+    fun categories_addsSameContentDescriptionForShortcutsOfSameType() {
+        testScope.runTest {
+            setCustomInputGestures(listOf(customInputGestureTypeHome))
+            systemShortcutsSource.setGroups(groupWithGoHomeShortcutInfo)
+            helper.showFromActivity()
+
+            val categories by collectLastValue(interactor.shortcutCategories)
+            val contentDescriptions =
+                categories?.flatMap {
+                    it.subCategories.flatMap { it.shortcuts.map { it.contentDescription } }
+                }
+
+            assertThat(contentDescriptions)
+                .containsExactly(
+                    "Go to home screen, Press key Ctrl plus Alt plus B, or Ctrl plus Alt plus A",
+                    "Standard shortcut 3, Press key Ctrl plus J",
+                    "Standard shortcut 2, Press key Alt plus Shift plus Z",
+                    "Standard shortcut 1, Press key Meta plus N",
+                    "Standard shortcut 1, Press key Meta plus N",
+                    "Standard shortcut 2, Press key Alt plus Shift plus Z",
+                    "Standard shortcut 3, Press key Ctrl plus J",
+                    "Switch to next language, Press key Ctrl plus Space",
+                    "Switch to previous language, Press key Ctrl plus Shift plus Space",
+                    "Standard shortcut 1, Press key Meta plus N",
+                    "Standard shortcut 2, Press key Alt plus Shift plus Z",
+                    "Standard shortcut 3, Press key Ctrl plus J",
+                    "Standard shortcut 3, Press key Ctrl plus J",
+                    "Standard shortcut 2, Press key Alt plus Shift plus Z",
+                    "Standard shortcut 1, Press key Meta plus N",
+                    "Standard shortcut 2, Press key Alt plus Shift plus Z",
+                    "Standard shortcut 1, Press key Meta plus N",
+                )
+        }
+    }
+
     private fun setCustomInputGestures(customInputGestures: List<InputGestureData>) {
         whenever(fakeInputManager.inputManager.getCustomInputGestures(/* filter= */ anyOrNull()))
             .thenReturn(customInputGestures)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
new file mode 100644
index 0000000..d0ce34c
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
@@ -0,0 +1,316 @@
+/*
+ * 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.keyboard.shortcut.ui.viewmodel
+
+import android.content.Context
+import android.content.Context.INPUT_SERVICE
+import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_ALREADY_EXISTS
+import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_OTHER
+import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_RESERVED_GESTURE
+import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_SUCCESS
+import android.hardware.input.fakeInputManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.allAppsInputGestureData
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.expectedStandardAddShortcutUiState
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.expectedStandardDeleteShortcutUiState
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.goHomeInputGestureData
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.keyDownEventWithActionKeyPressed
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.keyDownEventWithoutActionKeyPressed
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.keyUpEventWithActionKeyPressed
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.standardAddCustomShortcutRequestInfo
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.standardAddShortcutRequest
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.standardDeleteCustomShortcutRequestInfo
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
+import com.android.systemui.keyboard.shortcut.shortcutCustomizationViewModelFactory
+import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
+import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testCase
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.settings.userTracker
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ShortcutCustomizationViewModelTest : SysuiTestCase() {
+
+    private val mockUserContext: Context = mock()
+    private val kosmos =
+        Kosmos().also {
+            it.testCase = this
+            it.userTracker = FakeUserTracker(onCreateCurrentUserContext = { mockUserContext })
+        }
+    private val testScope = kosmos.testScope
+    private val inputManager = kosmos.fakeInputManager.inputManager
+    private val helper = kosmos.shortcutHelperTestHelper
+    private val viewModel = kosmos.shortcutCustomizationViewModelFactory.create()
+
+    @Before
+    fun setup() {
+        helper.showFromActivity()
+        whenever(mockUserContext.getSystemService(INPUT_SERVICE)).thenReturn(inputManager)
+    }
+
+    @Test
+    fun uiState_inactiveByDefault() {
+        testScope.runTest {
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+
+            assertThat(uiState).isEqualTo(ShortcutCustomizationUiState.Inactive)
+        }
+    }
+
+    @Test
+    fun uiState_correctlyUpdatedWhenAddShortcutCustomizationIsRequested() {
+        testScope.runTest {
+            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+
+            assertThat(uiState).isEqualTo(expectedStandardAddShortcutUiState)
+        }
+    }
+
+    @Test
+    fun uiState_correctlyUpdatedWhenDeleteShortcutCustomizationIsRequested() {
+        testScope.runTest {
+            viewModel.onShortcutCustomizationRequested(standardDeleteCustomShortcutRequestInfo)
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+
+            assertThat(uiState).isEqualTo(expectedStandardDeleteShortcutUiState)
+        }
+    }
+
+    @Test
+    fun uiState_consumedOnAddDialogShown() {
+        testScope.runTest {
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+            viewModel.onDialogShown()
+
+            assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).isDialogShowing)
+                .isTrue()
+        }
+    }
+
+    @Test
+    fun uiState_consumedOnDeleteDialogShown() {
+        testScope.runTest {
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+            viewModel.onShortcutCustomizationRequested(standardDeleteCustomShortcutRequestInfo)
+            viewModel.onDialogShown()
+
+            assertThat(
+                    (uiState as ShortcutCustomizationUiState.DeleteShortcutDialog).isDialogShowing
+                )
+                .isTrue()
+        }
+    }
+
+    @Test
+    fun uiState_inactiveAfterDialogIsDismissed() {
+        testScope.runTest {
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+            viewModel.onDialogShown()
+            viewModel.onDialogDismissed()
+            assertThat(uiState).isEqualTo(ShortcutCustomizationUiState.Inactive)
+        }
+    }
+
+    @Test
+    fun uiState_pressedKeys_emptyByDefault() {
+        testScope.runTest {
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+            assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).pressedKeys)
+                .isEmpty()
+        }
+    }
+
+    @Test
+    fun uiState_becomeInactiveAfterSuccessfullySettingShortcut() {
+        testScope.runTest {
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+            whenever(inputManager.addCustomInputGesture(any()))
+                .thenReturn(CUSTOM_INPUT_GESTURE_RESULT_SUCCESS)
+
+            openAddShortcutDialogAndSetShortcut()
+
+            assertThat(uiState).isEqualTo(ShortcutCustomizationUiState.Inactive)
+        }
+    }
+
+    @Test
+    fun uiState_errorMessage_isEmptyByDefault() {
+        testScope.runTest {
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+            viewModel.onShortcutCustomizationRequested(standardAddCustomShortcutRequestInfo)
+            viewModel.onDialogShown()
+
+            assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).errorMessage)
+                .isEmpty()
+        }
+    }
+
+    @Test
+    fun uiState_errorMessage_isKeyCombinationInUse_whenKeyCombinationAlreadyExists() {
+        testScope.runTest {
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+            whenever(inputManager.addCustomInputGesture(any()))
+                .thenReturn(CUSTOM_INPUT_GESTURE_RESULT_ERROR_ALREADY_EXISTS)
+
+            openAddShortcutDialogAndSetShortcut()
+
+            assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).errorMessage)
+                .isEqualTo(
+                    context.getString(
+                        R.string.shortcut_customizer_key_combination_in_use_error_message
+                    )
+                )
+        }
+    }
+
+    @Test
+    fun uiState_errorMessage_isKeyCombinationInUse_whenKeyCombinationIsReserved() {
+        testScope.runTest {
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+            whenever(inputManager.addCustomInputGesture(any()))
+                .thenReturn(CUSTOM_INPUT_GESTURE_RESULT_ERROR_RESERVED_GESTURE)
+
+            openAddShortcutDialogAndSetShortcut()
+
+            assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).errorMessage)
+                .isEqualTo(
+                    context.getString(
+                        R.string.shortcut_customizer_key_combination_in_use_error_message
+                    )
+                )
+        }
+    }
+
+    @Test
+    fun uiState_errorMessage_isGenericError_whenErrorIsUnknown() {
+        testScope.runTest {
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+            whenever(inputManager.addCustomInputGesture(any()))
+                .thenReturn(CUSTOM_INPUT_GESTURE_RESULT_ERROR_OTHER)
+
+            openAddShortcutDialogAndSetShortcut()
+
+            assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).errorMessage)
+                .isEqualTo(context.getString(R.string.shortcut_customizer_generic_error_message))
+        }
+    }
+
+    @Test
+    fun uiState_becomesInactiveAfterSuccessfullyDeletingShortcut() {
+        testScope.runTest {
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+            whenever(inputManager.getCustomInputGestures(any()))
+                .thenReturn(listOf(goHomeInputGestureData, allAppsInputGestureData))
+            whenever(inputManager.removeCustomInputGesture(any()))
+                .thenReturn(CUSTOM_INPUT_GESTURE_RESULT_SUCCESS)
+
+            openDeleteShortcutDialogAndDeleteShortcut()
+
+            assertThat(uiState).isEqualTo(ShortcutCustomizationUiState.Inactive)
+        }
+    }
+
+    @Test
+    fun onKeyPressed_handlesKeyEvents_whereActionKeyIsAlsoPressed() {
+        testScope.runTest {
+            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+            val isHandled = viewModel.onKeyPressed(keyDownEventWithActionKeyPressed)
+
+            assertThat(isHandled).isTrue()
+        }
+    }
+
+    @Test
+    fun onKeyPressed_doesNotHandleKeyEvents_whenActionKeyIsNotAlsoPressed() {
+        testScope.runTest {
+            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+            val isHandled = viewModel.onKeyPressed(keyDownEventWithoutActionKeyPressed)
+
+            assertThat(isHandled).isFalse()
+        }
+    }
+
+    @Test
+    fun onKeyPressed_convertsKeyEventsAndUpdatesUiStatesPressedKey() {
+        testScope.runTest {
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+            viewModel.onKeyPressed(keyDownEventWithActionKeyPressed)
+            viewModel.onKeyPressed(keyUpEventWithActionKeyPressed)
+
+            // Note that Action Key is excluded as it's already displayed on the UI
+            assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).pressedKeys)
+                .containsExactly(ShortcutKey.Text("Ctrl"), ShortcutKey.Text("A"))
+        }
+    }
+
+    @Test
+    fun uiState_pressedKeys_resetsToEmptyListAfterDialogIsDismissedAndReopened() {
+        testScope.runTest {
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+            viewModel.onKeyPressed(keyDownEventWithActionKeyPressed)
+            viewModel.onKeyPressed(keyUpEventWithActionKeyPressed)
+
+            // Note that Action Key is excluded as it's already displayed on the UI
+            assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).pressedKeys)
+                .containsExactly(ShortcutKey.Text("Ctrl"), ShortcutKey.Text("A"))
+
+            // Close the dialog and show it again
+            viewModel.onDialogDismissed()
+            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+            assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).pressedKeys)
+                .isEmpty()
+        }
+    }
+
+    private suspend fun openAddShortcutDialogAndSetShortcut() {
+        viewModel.onShortcutCustomizationRequested(standardAddCustomShortcutRequestInfo)
+        viewModel.onDialogShown()
+
+        viewModel.onKeyPressed(keyDownEventWithActionKeyPressed)
+        viewModel.onKeyPressed(keyUpEventWithActionKeyPressed)
+
+        viewModel.onSetShortcut()
+    }
+
+    private suspend fun openDeleteShortcutDialogAndDeleteShortcut() {
+        viewModel.onShortcutCustomizationRequested(standardDeleteCustomShortcutRequestInfo)
+        viewModel.onDialogShown()
+
+        viewModel.deleteShortcutCurrentlyBeingCustomized()
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
index 0329794..0a4198a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
@@ -32,7 +32,8 @@
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.test.runBlockingTest
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -125,14 +126,11 @@
             )
 
         underTest =
-            HomeControlsKeyguardQuickAffordanceConfig(
-                context = context,
-                component = component,
-            )
+            HomeControlsKeyguardQuickAffordanceConfig(context = context, component = component)
     }
 
     @Test
-    fun state() = runBlockingTest {
+    fun state() = runTest(UnconfinedTestDispatcher()) {
         whenever(component.isEnabled()).thenReturn(isFeatureEnabled)
         whenever(controlsController.getFavorites())
             .thenReturn(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
index 7d68cc0..0003d07 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
@@ -19,19 +19,20 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.Expandable
 import com.android.systemui.controls.controller.ControlsController
 import com.android.systemui.controls.dagger.ControlsComponent
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult
+import com.android.systemui.res.R
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import java.util.Optional
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.test.runBlockingTest
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -54,14 +55,11 @@
         whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(true))
 
         underTest =
-            HomeControlsKeyguardQuickAffordanceConfig(
-                context = context,
-                component = component,
-            )
+            HomeControlsKeyguardQuickAffordanceConfig(context = context, component = component)
     }
 
     @Test
-    fun state_whenCannotShowWhileLocked_returnsHidden() = runBlockingTest {
+    fun state_whenCannotShowWhileLocked_returnsHidden() = runTest(UnconfinedTestDispatcher()) {
         whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(false))
         whenever(component.isEnabled()).thenReturn(true)
         whenever(component.getTileImageId()).thenReturn(R.drawable.controls_icon)
@@ -81,7 +79,7 @@
     }
 
     @Test
-    fun state_whenListingControllerIsMissing_returnsHidden() = runBlockingTest {
+    fun state_whenListingControllerIsMissing_returnsHidden() = runTest(UnconfinedTestDispatcher()) {
         whenever(component.isEnabled()).thenReturn(true)
         whenever(component.getTileImageId()).thenReturn(R.drawable.controls_icon)
         whenever(component.getTileTitleId()).thenReturn(R.string.quick_controls_title)
@@ -100,23 +98,26 @@
     }
 
     @Test
-    fun onQuickAffordanceTriggered_canShowWhileLockedSettingIsTrue() = runBlockingTest {
-        whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(true))
+    fun onQuickAffordanceTriggered_canShowWhileLockedSettingIsTrue() =
+        runTest(UnconfinedTestDispatcher()) {
+            whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(true))
 
-        val onClickedResult = underTest.onTriggered(expandable)
+            val onClickedResult = underTest.onTriggered(expandable)
 
-        assertThat(onClickedResult).isInstanceOf(OnTriggeredResult.StartActivity::class.java)
-        assertThat((onClickedResult as OnTriggeredResult.StartActivity).canShowWhileLocked).isTrue()
-    }
+            assertThat(onClickedResult).isInstanceOf(OnTriggeredResult.StartActivity::class.java)
+            assertThat((onClickedResult as OnTriggeredResult.StartActivity).canShowWhileLocked)
+                .isTrue()
+        }
 
     @Test
-    fun onQuickAffordanceTriggered_canShowWhileLockedSettingIsFalse() = runBlockingTest {
-        whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(false))
+    fun onQuickAffordanceTriggered_canShowWhileLockedSettingIsFalse() =
+        runTest(UnconfinedTestDispatcher()) {
+            whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(false))
 
-        val onClickedResult = underTest.onTriggered(expandable)
+            val onClickedResult = underTest.onTriggered(expandable)
 
-        assertThat(onClickedResult).isInstanceOf(OnTriggeredResult.StartActivity::class.java)
-        assertThat((onClickedResult as OnTriggeredResult.StartActivity).canShowWhileLocked)
-            .isFalse()
-    }
+            assertThat(onClickedResult).isInstanceOf(OnTriggeredResult.StartActivity::class.java)
+            assertThat((onClickedResult as OnTriggeredResult.StartActivity).canShowWhileLocked)
+                .isFalse()
+        }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
index ca64cec..05a74c0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
@@ -29,7 +29,7 @@
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.test.runBlockingTest
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
@@ -56,60 +56,63 @@
     }
 
     @Test
-    fun affordance_setsUpRegistrationAndDeliversInitialModel() = runBlockingTest {
-        whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
-        var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
+    fun affordance_setsUpRegistrationAndDeliversInitialModel() =
+        runTest(UnconfinedTestDispatcher()) {
+            whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
+            var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
 
-        val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
+            val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
 
-        val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
-        verify(controller).addCallback(callbackCaptor.capture())
-        verify(controller)
-            .registerQRCodeScannerChangeObservers(
-                QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
-                QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE
-            )
-        assertVisibleState(latest)
+            val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
+            verify(controller).addCallback(callbackCaptor.capture())
+            verify(controller)
+                .registerQRCodeScannerChangeObservers(
+                    QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
+                    QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE,
+                )
+            assertVisibleState(latest)
 
-        job.cancel()
-        verify(controller).removeCallback(callbackCaptor.value)
-    }
+            job.cancel()
+            verify(controller).removeCallback(callbackCaptor.value)
+        }
 
     @Test
-    fun affordance_scannerActivityChanged_deliversModelWithUpdatedIntent() = runBlockingTest {
-        whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
-        var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
-        val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
-        val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
-        verify(controller).addCallback(callbackCaptor.capture())
+    fun affordance_scannerActivityChanged_deliversModelWithUpdatedIntent() =
+        runTest(UnconfinedTestDispatcher()) {
+            whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
+            var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
+            val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
+            val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
+            verify(controller).addCallback(callbackCaptor.capture())
 
-        whenever(controller.intent).thenReturn(INTENT_2)
-        callbackCaptor.value.onQRCodeScannerActivityChanged()
+            whenever(controller.intent).thenReturn(INTENT_2)
+            callbackCaptor.value.onQRCodeScannerActivityChanged()
 
-        assertVisibleState(latest)
+            assertVisibleState(latest)
 
-        job.cancel()
-        verify(controller).removeCallback(callbackCaptor.value)
-    }
+            job.cancel()
+            verify(controller).removeCallback(callbackCaptor.value)
+        }
 
     @Test
-    fun affordance_scannerPreferenceChanged_deliversVisibleModel() = runBlockingTest {
-        var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
-        val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
-        val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
-        verify(controller).addCallback(callbackCaptor.capture())
+    fun affordance_scannerPreferenceChanged_deliversVisibleModel() =
+        runTest(UnconfinedTestDispatcher()) {
+            var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
+            val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
+            val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
+            verify(controller).addCallback(callbackCaptor.capture())
 
-        whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
-        callbackCaptor.value.onQRCodeScannerPreferenceChanged()
+            whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
+            callbackCaptor.value.onQRCodeScannerPreferenceChanged()
 
-        assertVisibleState(latest)
+            assertVisibleState(latest)
 
-        job.cancel()
-        verify(controller).removeCallback(callbackCaptor.value)
-    }
+            job.cancel()
+            verify(controller).removeCallback(callbackCaptor.value)
+        }
 
     @Test
-    fun affordance_scannerPreferenceChanged_deliversNone() = runBlockingTest {
+    fun affordance_scannerPreferenceChanged_deliversNone() = runTest(UnconfinedTestDispatcher()) {
         var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
         val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
         val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
@@ -128,30 +131,29 @@
     fun onQuickAffordanceTriggered() {
         assertThat(underTest.onTriggered(mock()))
             .isEqualTo(
-                OnTriggeredResult.StartActivity(
-                    intent = INTENT_1,
-                    canShowWhileLocked = true,
-                )
+                OnTriggeredResult.StartActivity(intent = INTENT_1, canShowWhileLocked = true)
             )
     }
 
     @Test
-    fun getPickerScreenState_enabledIfConfiguredOnDevice_isEnabledForPickerState() = runTest {
-        whenever(controller.isAllowedOnLockScreen).thenReturn(true)
-        whenever(controller.isAbleToLaunchScannerActivity).thenReturn(true)
+    fun getPickerScreenState_enabledIfConfiguredOnDevice_isEnabledForPickerState() =
+        runTest(UnconfinedTestDispatcher()) {
+            whenever(controller.isAllowedOnLockScreen).thenReturn(true)
+            whenever(controller.isAbleToLaunchScannerActivity).thenReturn(true)
 
-        assertThat(underTest.getPickerScreenState())
-            .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.Default())
-    }
+            assertThat(underTest.getPickerScreenState())
+                .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.Default())
+        }
 
     @Test
-    fun getPickerScreenState_disabledIfConfiguredOnDevice_isDisabledForPickerState() = runTest {
-        whenever(controller.isAllowedOnLockScreen).thenReturn(true)
-        whenever(controller.isAbleToLaunchScannerActivity).thenReturn(false)
+    fun getPickerScreenState_disabledIfConfiguredOnDevice_isDisabledForPickerState() =
+        runTest(UnconfinedTestDispatcher()) {
+            whenever(controller.isAllowedOnLockScreen).thenReturn(true)
+            whenever(controller.isAbleToLaunchScannerActivity).thenReturn(false)
 
-        assertThat(underTest.getPickerScreenState())
-            .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
-    }
+            assertThat(underTest.getPickerScreenState())
+                .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
+        }
 
     private fun assertVisibleState(latest: KeyguardQuickAffordanceConfig.LockScreenState?) {
         assertThat(latest)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
index e149687..dadcf71 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
@@ -35,10 +35,9 @@
 import com.android.systemui.keyguard.shared.model.DismissAction
 import com.android.systemui.keyguard.shared.model.KeyguardDone
 import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
 import com.android.systemui.kosmos.testScope
-import com.android.systemui.power.data.repository.fakePowerRepository
-import com.android.systemui.power.shared.model.WakeSleepReason
-import com.android.systemui.power.shared.model.WakefulnessState
 import com.android.systemui.scene.data.repository.Idle
 import com.android.systemui.scene.data.repository.Transition
 import com.android.systemui.scene.data.repository.setSceneTransition
@@ -222,28 +221,6 @@
         }
 
     @Test
-    fun resetDismissAction() =
-        testScope.runTest {
-            kosmos.setSceneTransition(Idle(Scenes.Bouncer))
-            var wasOnCancelInvoked = false
-            startInteractor()
-            keyguardRepository.setDismissAction(
-                DismissAction.RunAfterKeyguardGone(
-                    dismissAction = {},
-                    onCancelAction = { wasOnCancelInvoked = true },
-                    message = "message",
-                    willAnimateOnLockscreen = true,
-                )
-            )
-            assertThat(wasOnCancelInvoked).isFalse()
-            kosmos.setSceneTransition(Idle(Scenes.Lockscreen))
-            runCurrent()
-
-            assertThat(wasOnCancelInvoked).isTrue()
-            assertThat(keyguardRepository.dismissAction.value).isEqualTo(DismissAction.None)
-        }
-
-    @Test
     fun doNotResetDismissActionOnUnlockedShade() =
         testScope.runTest {
             kosmos.setSceneTransition(Idle(Scenes.Bouncer))
@@ -272,37 +249,6 @@
         }
 
     @Test
-    fun resetDismissAction_onBouncer_OnAsleep() =
-        testScope.runTest {
-            kosmos.setSceneTransition(Idle(Scenes.Bouncer))
-            kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
-                AuthenticationMethodModel.None
-            )
-            var wasOnCancelInvoked = false
-            startInteractor()
-
-            keyguardRepository.setDismissAction(
-                DismissAction.RunAfterKeyguardGone(
-                    dismissAction = {},
-                    onCancelAction = { wasOnCancelInvoked = true },
-                    message = "message",
-                    willAnimateOnLockscreen = true,
-                )
-            )
-            assertThat(wasOnCancelInvoked).isFalse()
-            kosmos.fakePowerRepository.updateWakefulness(
-                rawState = WakefulnessState.ASLEEP,
-                lastWakeReason = WakeSleepReason.POWER_BUTTON,
-                lastSleepReason = WakeSleepReason.TIMEOUT,
-                powerButtonLaunchGestureTriggered = false,
-            )
-            runCurrent()
-
-            assertThat(wasOnCancelInvoked).isTrue()
-            assertThat(keyguardRepository.dismissAction.value).isEqualTo(DismissAction.None)
-        }
-
-    @Test
     fun setDismissAction_callsCancelRunnableOnPreviousDismissAction() =
         testScope.runTest {
             val dismissAction by collectLastValue(keyguardRepository.dismissAction)
@@ -410,6 +356,25 @@
             assertThat(wasCancelActionInvoked).isFalse()
         }
 
+    @Test
+    fun clearDismissAction() =
+        kosmos.runTest {
+            val dismissAction by collectLastValue(fakeKeyguardRepository.dismissAction)
+            fakeKeyguardRepository.setDismissAction(
+                DismissAction.RunImmediately(
+                    onDismissAction = { KeyguardDone.IMMEDIATE },
+                    onCancelAction = {},
+                    message = "",
+                    willAnimateOnLockscreen = true,
+                )
+            )
+            assertThat(dismissAction).isNotEqualTo(DismissAction.None)
+
+            underTest.clearDismissAction()
+
+            assertThat(dismissAction).isEqualTo(DismissAction.None)
+        }
+
     private fun TestScope.startInteractor() {
         testScope.backgroundScope.launchTraced(
             "KeyguardDismissActionInteractorTest#startInteractor"
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLockWhileAwakeInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLockWhileAwakeInteractorTest.kt
index bd26e42..bef995f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLockWhileAwakeInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLockWhileAwakeInteractorTest.kt
@@ -18,6 +18,7 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.internal.widget.lockPatternUtils
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
@@ -33,6 +34,8 @@
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.kotlin.whenever
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
@@ -52,14 +55,21 @@
         testScope.runTest {
             val values by collectValues(underTest.lockWhileAwakeEvents)
 
-            underTest.onKeyguardServiceDoKeyguardTimeout(options = null)
+            kosmos.keyguardEnabledInteractor.notifyKeyguardEnabled(true)
+            runCurrent()
+
+            kosmos.keyguardServiceLockNowInteractor.onKeyguardServiceDoKeyguardTimeout(
+                options = null
+            )
             runCurrent()
 
             assertThat(values)
                 .containsExactly(LockWhileAwakeReason.KEYGUARD_TIMEOUT_WHILE_SCREEN_ON)
 
             advanceTimeBy(1000)
-            underTest.onKeyguardServiceDoKeyguardTimeout(options = null)
+            kosmos.keyguardServiceLockNowInteractor.onKeyguardServiceDoKeyguardTimeout(
+                options = null
+            )
             runCurrent()
 
             assertThat(values)
@@ -69,8 +79,15 @@
                 )
         }
 
+    /**
+     * We re-show keyguard when it's re-enabled, but only if it was originally showing when we
+     * disabled it.
+     *
+     * If it wasn't showing when originally disabled it, re-enabling it should do nothing (the
+     * keyguard will re-show next time we're locked).
+     */
     @Test
-    fun emitsWhenKeyguardEnabled_onlyIfShowingWhenDisabled() =
+    fun emitsWhenKeyguardReenabled_onlyIfShowingWhenDisabled() =
         testScope.runTest {
             val values by collectValues(underTest.lockWhileAwakeEvents)
 
@@ -98,4 +115,49 @@
 
             assertThat(values).containsExactly(LockWhileAwakeReason.KEYGUARD_REENABLED)
         }
+
+    /**
+     * Un-suppressing keyguard should never cause us to re-show. We'll re-show when we're next
+     * locked, even if we were showing when originally suppressed.
+     */
+    @Test
+    fun doesNotEmit_keyguardNoLongerSuppressed() =
+        testScope.runTest {
+            val values by collectValues(underTest.lockWhileAwakeEvents)
+
+            // Enable keyguard and then suppress it.
+            kosmos.keyguardEnabledInteractor.notifyKeyguardEnabled(true)
+            whenever(kosmos.lockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(true)
+            runCurrent()
+
+            assertEquals(0, values.size)
+
+            // Un-suppress keyguard.
+            whenever(kosmos.lockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(false)
+            runCurrent()
+
+            assertEquals(0, values.size)
+        }
+
+    /**
+     * Lockdown and lockNow() should not cause us to lock while awake if we are suppressed via adb.
+     */
+    @Test
+    fun doesNotEmit_fromLockdown_orFromLockNow_ifEnabledButSuppressed() =
+        testScope.runTest {
+            val values by collectValues(underTest.lockWhileAwakeEvents)
+
+            // Set keyguard enabled, but then disable lockscreen (suppress it).
+            kosmos.keyguardEnabledInteractor.notifyKeyguardEnabled(true)
+            whenever(kosmos.lockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(true)
+            runCurrent()
+
+            kosmos.keyguardServiceLockNowInteractor.onKeyguardServiceDoKeyguardTimeout(null)
+            runCurrent()
+
+            kosmos.biometricSettingsRepository.setIsUserInLockdown(true)
+            runCurrent()
+
+            assertEquals(0, values.size)
+        }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorTest.kt
index 7e249e8..ead151e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorTest.kt
@@ -87,9 +87,9 @@
 
             assertEquals(
                 listOf(
-                    false, // Defaults to false.
+                    false // Defaults to false.
                 ),
-                canWake
+                canWake,
             )
 
             repository.setKeyguardEnabled(false)
@@ -100,33 +100,26 @@
                     false, // Default to false.
                     true, // True now that keyguard service is disabled
                 ),
-                canWake
+                canWake,
             )
 
             repository.setKeyguardEnabled(true)
             runCurrent()
 
-            assertEquals(
-                listOf(
-                    false,
-                    true,
-                    false,
-                ),
-                canWake
-            )
+            assertEquals(listOf(false, true, false), canWake)
         }
 
     @Test
     @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
-    fun testCanWakeDirectlyToGone_lockscreenDisabledThenEnabled() =
+    fun testCanWakeDirectlyToGone_lockscreenDisabledThenEnabled_onlyAfterWakefulnessChange() =
         testScope.runTest {
             val canWake by collectValues(underTest.canWakeDirectlyToGone)
 
             assertEquals(
                 listOf(
-                    false, // Defaults to false.
+                    false // Defaults to false.
                 ),
-                canWake
+                canWake,
             )
 
             whenever(lockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(true)
@@ -136,9 +129,9 @@
                 listOf(
                     // Still false - isLockScreenDisabled only causes canWakeDirectlyToGone to
                     // update on the next wake/sleep event.
-                    false,
+                    false
                 ),
-                canWake
+                canWake,
             )
 
             kosmos.powerInteractor.setAsleepForTest()
@@ -150,7 +143,7 @@
                     // True since we slept after setting isLockScreenDisabled=true
                     true,
                 ),
-                canWake
+                canWake,
             )
 
             kosmos.powerInteractor.setAwakeForTest()
@@ -159,25 +152,75 @@
             kosmos.powerInteractor.setAsleepForTest()
             runCurrent()
 
-            assertEquals(
-                listOf(
-                    false,
-                    true,
-                ),
-                canWake
-            )
+            assertEquals(listOf(false, true), canWake)
 
             whenever(lockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(false)
             kosmos.powerInteractor.setAwakeForTest()
             runCurrent()
 
+            assertEquals(listOf(false, true, false), canWake)
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
+    fun testCanWakeDirectlyToGone_lockscreenDisabledThenEnabled_lockNowEvent() =
+        testScope.runTest {
+            val canWake by collectValues(underTest.canWakeDirectlyToGone)
+
+            assertEquals(
+                listOf(
+                    false // Defaults to false.
+                ),
+                canWake,
+            )
+
+            whenever(lockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(true)
+            runCurrent()
+
+            assertEquals(
+                listOf(
+                    // Still false - isLockScreenDisabled only causes canWakeDirectlyToGone to
+                    // update on the next wakefulness or lockNow event.
+                    false
+                ),
+                canWake,
+            )
+
+            kosmos.keyguardServiceLockNowInteractor.onKeyguardServiceDoKeyguardTimeout(null)
+            runCurrent()
+
+            assertEquals(
+                listOf(
+                    false,
+                    // True when lockNow() called after setting isLockScreenDisabled=true
+                    true,
+                ),
+                canWake,
+            )
+
+            whenever(lockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(false)
+            runCurrent()
+
+            assertEquals(
+                listOf(
+                    false,
+                    // Still true since no lockNow() calls made.
+                    true,
+                ),
+                canWake,
+            )
+
+            kosmos.keyguardServiceLockNowInteractor.onKeyguardServiceDoKeyguardTimeout(null)
+            runCurrent()
+
             assertEquals(
                 listOf(
                     false,
                     true,
+                    // False again after the lockNow() call.
                     false,
                 ),
-                canWake
+                canWake,
             )
         }
 
@@ -189,9 +232,9 @@
 
             assertEquals(
                 listOf(
-                    false, // Defaults to false.
+                    false // Defaults to false.
                 ),
-                canWake
+                canWake,
             )
 
             repository.setBiometricUnlockState(BiometricUnlockMode.WAKE_AND_UNLOCK)
@@ -213,9 +256,9 @@
 
             assertEquals(
                 listOf(
-                    false, // Defaults to false.
+                    false // Defaults to false.
                 ),
-                canWake
+                canWake,
             )
 
             repository.setCanIgnoreAuthAndReturnToGone(true)
@@ -237,9 +280,9 @@
 
             assertEquals(
                 listOf(
-                    false, // Defaults to false.
+                    false // Defaults to false.
                 ),
-                canWake
+                canWake,
             )
 
             whenever(kosmos.devicePolicyManager.getMaximumTimeToLock(eq(null), anyInt()))
@@ -257,13 +300,7 @@
             )
             runCurrent()
 
-            assertEquals(
-                listOf(
-                    false,
-                    true,
-                ),
-                canWake
-            )
+            assertEquals(listOf(false, true), canWake)
 
             verify(kosmos.alarmManager)
                 .setExactAndAllowWhileIdle(
@@ -281,9 +318,9 @@
 
             assertEquals(
                 listOf(
-                    false, // Defaults to false.
+                    false // Defaults to false.
                 ),
-                canWake
+                canWake,
             )
 
             whenever(kosmos.devicePolicyManager.getMaximumTimeToLock(eq(null), anyInt()))
@@ -312,7 +349,7 @@
                     // Timed out, so we can ignore auth/return to GONE.
                     true,
                 ),
-                canWake
+                canWake,
             )
 
             verify(kosmos.alarmManager)
@@ -338,7 +375,7 @@
                     // alarm in flight that should be canceled.
                     false,
                 ),
-                canWake
+                canWake,
             )
 
             kosmos.powerInteractor.setAsleepForTest(
@@ -354,25 +391,17 @@
                     // Back to sleep.
                     true,
                 ),
-                canWake
+                canWake,
             )
 
             // Simulate the first sleep's alarm coming in.
             lastRegisteredBroadcastReceiver?.onReceive(
                 kosmos.mockedContext,
-                Intent("com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD")
+                Intent("com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD"),
             )
             runCurrent()
 
             // It should not have any effect.
-            assertEquals(
-                listOf(
-                    false,
-                    true,
-                    false,
-                    true,
-                ),
-                canWake
-            )
+            assertEquals(listOf(false, true, false, true), canWake)
         }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
index 2c12f87..2101987 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
@@ -24,6 +24,7 @@
 import com.android.systemui.authentication.domain.interactor.authenticationInteractor
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.coroutines.collectValues
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
 import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
 import com.android.systemui.flags.DisableSceneContainer
 import com.android.systemui.flags.EnableSceneContainer
@@ -34,10 +35,12 @@
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.data.model.asIterable
+import com.android.systemui.scene.data.model.sceneStackOf
 import com.android.systemui.scene.data.repository.Idle
 import com.android.systemui.scene.data.repository.Transition
-import com.android.systemui.scene.data.repository.sceneContainerRepository
 import com.android.systemui.scene.data.repository.setSceneTransition
+import com.android.systemui.scene.domain.interactor.sceneBackInteractor
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.testKosmos
@@ -52,6 +55,7 @@
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -85,7 +89,7 @@
     fun setUp() {
         // lazy value needs to be called here otherwise flow collection misbehaves
         underTest.value
-        kosmos.sceneContainerRepository.setTransitionState(sceneTransitions)
+        kosmos.setSceneTransition(ObservableTransitionState.Idle(Scenes.Lockscreen))
     }
 
     @Test
@@ -883,6 +887,7 @@
 
     @Test
     @EnableSceneContainer
+    @Ignore("b/378766637")
     fun lockscreenVisibilityWithScenes() =
         testScope.runTest {
             val isDeviceUnlocked by
@@ -967,15 +972,56 @@
 
     @Test
     @EnableSceneContainer
+    fun lockscreenVisibilityWithScenes_staysTrue_despiteEnteringIndirectly() =
+        testScope.runTest {
+            val isDeviceUnlocked by
+                collectLastValue(
+                    kosmos.deviceUnlockedInteractor.deviceUnlockStatus.map { it.isUnlocked }
+                )
+            assertThat(isDeviceUnlocked).isFalse()
+
+            val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+
+            val lockscreenVisibility by collectLastValue(underTest.value.lockscreenVisibility)
+            assertThat(lockscreenVisibility).isTrue()
+
+            kosmos.setSceneTransition(Idle(Scenes.Shade))
+            kosmos.sceneInteractor.changeScene(Scenes.Shade, "")
+            kosmos.sceneBackInteractor.onSceneChange(from = Scenes.Lockscreen, to = Scenes.Shade)
+            assertThat(currentScene).isEqualTo(Scenes.Shade)
+            assertThat(lockscreenVisibility).isTrue()
+            val sceneBackStack by collectLastValue(kosmos.sceneBackInteractor.backStack)
+            assertThat(sceneBackStack?.asIterable()?.toList()).isEqualTo(listOf(Scenes.Lockscreen))
+
+            val isDeviceEntered by collectLastValue(kosmos.deviceEntryInteractor.isDeviceEntered)
+            val isDeviceEnteredDirectly by
+                collectLastValue(kosmos.deviceEntryInteractor.isDeviceEnteredDirectly)
+            runCurrent()
+            assertThat(isDeviceEntered).isFalse()
+            assertThat(isDeviceEnteredDirectly).isFalse()
+
+            kosmos.authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)
+            kosmos.sceneBackInteractor.updateBackStack { sceneStackOf(Scenes.Gone) }
+            assertThat(sceneBackStack?.asIterable()?.toList()).isEqualTo(listOf(Scenes.Gone))
+
+            assertThat(isDeviceEntered).isTrue()
+            assertThat(isDeviceEnteredDirectly).isFalse()
+            assertThat(isDeviceUnlocked).isTrue()
+            assertThat(lockscreenVisibility).isTrue()
+        }
+
+    @Test
+    @EnableSceneContainer
     fun sceneContainer_usingGoingAwayAnimation_duringTransitionToGone() =
         testScope.runTest {
             val usingKeyguardGoingAwayAnimation by
                 collectLastValue(underTest.value.usingKeyguardGoingAwayAnimation)
 
-            sceneTransitions.value = lsToGone
+            kosmos.setSceneTransition(lsToGone)
             assertThat(usingKeyguardGoingAwayAnimation).isTrue()
 
-            sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
+            kosmos.setSceneTransition(ObservableTransitionState.Idle(Scenes.Gone))
             assertThat(usingKeyguardGoingAwayAnimation).isFalse()
         }
 
@@ -986,14 +1032,14 @@
             val usingKeyguardGoingAwayAnimation by
                 collectLastValue(underTest.value.usingKeyguardGoingAwayAnimation)
 
-            sceneTransitions.value = lsToGone
+            kosmos.setSceneTransition(lsToGone)
             surfaceBehindIsAnimatingFlow.emit(true)
             assertThat(usingKeyguardGoingAwayAnimation).isTrue()
 
-            sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
+            kosmos.setSceneTransition(ObservableTransitionState.Idle(Scenes.Gone))
             assertThat(usingKeyguardGoingAwayAnimation).isTrue()
 
-            sceneTransitions.value = goneToLs
+            kosmos.setSceneTransition(goneToLs)
             assertThat(usingKeyguardGoingAwayAnimation).isTrue()
 
             surfaceBehindIsAnimatingFlow.emit(false)
@@ -1003,11 +1049,6 @@
     companion object {
         private val progress = MutableStateFlow(0f)
 
-        private val sceneTransitions =
-            MutableStateFlow<ObservableTransitionState>(
-                ObservableTransitionState.Idle(Scenes.Lockscreen)
-            )
-
         private val lsToGone =
             ObservableTransitionState.Transition(
                 Scenes.Lockscreen,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelTest.kt
index 5c4b743..62cc763 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelTest.kt
@@ -32,12 +32,11 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
 import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
-import com.android.systemui.communal.domain.interactor.communalInteractor
 import com.android.systemui.communal.domain.interactor.setCommunalAvailable
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
-import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
 import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.lifecycle.activateIn
 import com.android.systemui.power.data.repository.fakePowerRepository
@@ -48,7 +47,6 @@
 import com.android.systemui.scene.shared.model.TransitionKeys
 import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge
 import com.android.systemui.shade.data.repository.shadeRepository
-import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlin.math.pow
@@ -69,12 +67,13 @@
 class LockscreenUserActionsViewModelTest : SysuiTestCase() {
 
     companion object {
-        private const val parameterCount = 6
+        private const val parameterCount = 7
 
         @Parameters(
             name =
                 "canSwipeToEnter={0}, downWithTwoPointers={1}, downFromEdge={2}," +
-                    " isSingleShade={3}, isCommunalAvailable={4}, isShadeTouchable={5}"
+                    " isSingleShade={3}, isCommunalAvailable={4}, isShadeTouchable={5}," +
+                    " isOccluded={6}"
         )
         @JvmStatic
         fun combinations() = buildList {
@@ -87,6 +86,7 @@
                             /* isSingleShade= */ combination and 8 != 0,
                             /* isCommunalAvailable= */ combination and 16 != 0,
                             /* isShadeTouchable= */ combination and 32 != 0,
+                            /* isOccluded= */ combination and 64 != 0,
                         )
                         .also { check(it.size == parameterCount) }
                 )
@@ -116,10 +116,12 @@
             downFromEdge: Boolean,
             isNarrowScreen: Boolean,
             isShadeTouchable: Boolean,
+            isOccluded: Boolean,
         ): SceneKey? {
             return when {
                 !isShadeTouchable -> null
-                downFromEdge && isNarrowScreen -> Scenes.QuickSettings
+                downFromEdge && isNarrowScreen && !isOccluded -> Scenes.QuickSettings
+                downFromEdge && isNarrowScreen && isOccluded -> null
                 else -> Scenes.Shade
             }
         }
@@ -168,8 +170,9 @@
     @JvmField @Parameter(3) var isNarrowScreen: Boolean = true
     @JvmField @Parameter(4) var isCommunalAvailable: Boolean = false
     @JvmField @Parameter(5) var isShadeTouchable: Boolean = false
+    @JvmField @Parameter(6) var isOccluded: Boolean = false
 
-    private val underTest by lazy { createLockscreenSceneViewModel() }
+    private val underTest by lazy { kosmos.lockscreenUserActionsViewModel }
 
     @Test
     @EnableFlags(Flags.FLAG_COMMUNAL_HUB)
@@ -196,6 +199,7 @@
                         WakefulnessState.ASLEEP
                     }
             )
+            kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(onTop = isOccluded)
 
             val userActions by collectLastValue(underTest.actions)
             val downDestination =
@@ -217,6 +221,7 @@
                         downFromEdge = downFromEdge,
                         isNarrowScreen = isNarrowScreen,
                         isShadeTouchable = isShadeTouchable,
+                        isOccluded = isOccluded,
                     )
                 )
 
@@ -285,6 +290,7 @@
                         WakefulnessState.ASLEEP
                     }
             )
+            kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(onTop = isOccluded)
 
             val userActions by collectLastValue(underTest.actions)
 
@@ -354,12 +360,4 @@
                     )
                 )
         }
-
-    private fun createLockscreenSceneViewModel(): LockscreenUserActionsViewModel {
-        return LockscreenUserActionsViewModel(
-            deviceEntryInteractor = kosmos.deviceEntryInteractor,
-            communalInteractor = kosmos.communalInteractor,
-            shadeInteractor = kosmos.shadeInteractor,
-        )
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
index 02825a5..ff00bfb5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
@@ -18,6 +18,7 @@
 
 import android.hardware.display.displayManager
 import android.media.projection.MediaProjectionInfo
+import android.media.projection.StopReason
 import android.os.Binder
 import android.os.Handler
 import android.os.UserHandle
@@ -339,8 +340,9 @@
     @Test
     fun stopProjecting_invokesManager() =
         testScope.runTest {
-            repo.stopProjecting()
+            repo.stopProjecting(StopReason.STOP_QS_TILE)
 
-            verify(fakeMediaProjectionManager.mediaProjectionManager).stopActiveProjection()
+            verify(fakeMediaProjectionManager.mediaProjectionManager)
+                .stopActiveProjection(StopReason.STOP_QS_TILE)
         }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java
index 646722b..555ba56 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java
@@ -90,6 +90,7 @@
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.NavBarHelper;
 import com.android.systemui.navigationbar.NavigationBarController;
@@ -116,8 +117,7 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.data.repository.LightBarControllerStore;
-import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.AutoHideControllerStore;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.LightBarTransitionsController;
@@ -148,6 +148,7 @@
 @SmallTest
 public class NavigationBarTest extends SysuiTestCase {
     private static final int EXTERNAL_DISPLAY_ID = 2;
+    private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
 
     private NavigationBar mNavigationBar;
     private NavigationBar mExternalDisplayNavigationBar;
@@ -209,11 +210,7 @@
     @Mock
     private LightBarController mLightBarController;
     @Mock
-    private LightBarControllerStore mLightBarControllerStore;
-    @Mock
-    private AutoHideController mAutoHideController;
-    @Mock
-    private AutoHideController.Factory mAutoHideControllerFactory;
+    private LightBarController.Factory mLightBarcontrollerFactory;
     @Mock
     private WindowManager mWindowManager;
     @Mock
@@ -248,6 +245,8 @@
     private DeviceConfigProxyFake mDeviceConfigProxyFake = new DeviceConfigProxyFake();
     private TaskStackChangeListeners mTaskStackChangeListeners =
             TaskStackChangeListeners.getTestInstance();
+    private final AutoHideControllerStore mAutoHideControllerStore =
+            mKosmos.getAutoHideControllerStore();
 
     @Rule
     public final LeakCheckedTest.SysuiLeakCheck mLeakCheck = new LeakCheckedTest.SysuiLeakCheck();
@@ -258,8 +257,7 @@
     public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
 
-        when(mLightBarControllerStore.forDisplay(anyInt())).thenReturn(mLightBarController);
-        when(mAutoHideControllerFactory.create(any(Context.class))).thenReturn(mAutoHideController);
+        when(mLightBarcontrollerFactory.create(any(Context.class))).thenReturn(mLightBarController);
         when(mNavigationBarView.getHomeButton()).thenReturn(mHomeButton);
         when(mNavigationBarView.getRecentsButton()).thenReturn(mRecentsButton);
         when(mNavigationBarView.getAccessibilityButton()).thenReturn(mAccessibilityButton);
@@ -650,9 +648,9 @@
                 mFakeExecutor,
                 mUiEventLogger,
                 mNavBarHelper,
-                mLightBarControllerStore,
-                mAutoHideController,
-                mAutoHideControllerFactory,
+                mLightBarController,
+                mLightBarcontrollerFactory,
+                mAutoHideControllerStore,
                 Optional.of(mTelecomManager),
                 mInputMethodManager,
                 mDeadZone,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/AbstractQSFragmentComposeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/AbstractQSFragmentComposeViewModelTest.kt
index b5fc52f..87e2fef 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/AbstractQSFragmentComposeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/AbstractQSFragmentComposeViewModelTest.kt
@@ -16,11 +16,13 @@
 
 package com.android.systemui.qs.composefragment.viewmodel
 
+import androidx.compose.runtime.snapshots.Snapshot
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.testing.TestLifecycleOwner
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.runCurrent
 import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.lifecycle.activateIn
@@ -36,7 +38,6 @@
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import kotlinx.coroutines.test.setMain
-import org.junit.After
 import org.junit.Before
 import org.junit.runner.RunWith
 
@@ -58,11 +59,14 @@
     @Before
     fun setUp() {
         Dispatchers.setMain(kosmos.testDispatcher)
-    }
+        onTeardown { Dispatchers.resetMain() }
 
-    @After
-    fun teardown() {
-        Dispatchers.resetMain()
+        val globalWriteObserverHandle =
+            Snapshot.registerGlobalWriteObserver {
+                Snapshot.sendApplyNotifications()
+                kosmos.runCurrent()
+            }
+        onTeardown { globalWriteObserverHandle.dispose() }
     }
 
     protected inline fun TestScope.testWithinLifecycle(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt
index 921a8a6..111b3b6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt
@@ -20,7 +20,6 @@
 import android.content.testableContext
 import android.graphics.Rect
 import android.testing.TestableLooper.RunWithLooper
-import androidx.compose.runtime.snapshots.Snapshot
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
@@ -186,15 +185,12 @@
                 val squishiness by collectLastValue(tileSquishinessInteractor.squishiness)
 
                 underTest.squishinessFraction = 0.3f
-                Snapshot.sendApplyNotifications()
                 assertThat(squishiness).isWithin(epsilon).of(0.3f.constrainSquishiness())
 
                 underTest.squishinessFraction = 0f
-                Snapshot.sendApplyNotifications()
                 assertThat(squishiness).isWithin(epsilon).of(0f.constrainSquishiness())
 
                 underTest.squishinessFraction = 1f
-                Snapshot.sendApplyNotifications()
                 assertThat(squishiness).isWithin(epsilon).of(1f.constrainSquishiness())
             }
         }
@@ -328,13 +324,9 @@
                 setMediaState(ACTIVE_MEDIA)
 
                 setConfigurationForMediaInRow(mediaInRow = false)
-                Snapshot.sendApplyNotifications()
-                runCurrent()
                 assertThat(underTest.qqsMediaHost.expansion).isEqualTo(MediaHostState.EXPANDED)
 
                 setConfigurationForMediaInRow(mediaInRow = true)
-                Snapshot.sendApplyNotifications()
-                runCurrent()
                 assertThat(underTest.qqsMediaHost.expansion).isEqualTo(MediaHostState.COLLAPSED)
             }
         }
@@ -347,13 +339,9 @@
                 setMediaState(ACTIVE_MEDIA)
 
                 setConfigurationForMediaInRow(mediaInRow = false)
-                Snapshot.sendApplyNotifications()
-                runCurrent()
                 assertThat(underTest.qqsMediaHost.expansion).isEqualTo(MediaHostState.EXPANDED)
 
                 setConfigurationForMediaInRow(mediaInRow = true)
-                Snapshot.sendApplyNotifications()
-                runCurrent()
                 assertThat(underTest.qqsMediaHost.expansion).isEqualTo(MediaHostState.EXPANDED)
             }
         }
@@ -366,13 +354,9 @@
                 setMediaState(ACTIVE_MEDIA)
 
                 setCollapsedMediaInLandscape(false)
-                Snapshot.sendApplyNotifications()
-                runCurrent()
                 assertThat(underTest.qqsMediaHost.expansion).isEqualTo(MediaHostState.EXPANDED)
 
                 setCollapsedMediaInLandscape(true)
-                Snapshot.sendApplyNotifications()
-                runCurrent()
                 assertThat(underTest.qqsMediaHost.expansion).isEqualTo(MediaHostState.COLLAPSED)
             }
         }
@@ -401,13 +385,11 @@
                 underTest.squishinessFraction = 0.3f
 
                 underTest.shouldUpdateSquishinessOnMedia = true
-                Snapshot.sendApplyNotifications()
                 runCurrent()
 
                 assertThat(underTest.qsMediaHost.squishFraction).isWithin(0.01f).of(0.3f)
 
                 underTest.shouldUpdateSquishinessOnMedia = false
-                Snapshot.sendApplyNotifications()
                 runCurrent()
                 assertThat(underTest.qsMediaHost.squishFraction).isWithin(0.01f).of(1f)
             }
@@ -421,20 +403,15 @@
                 underTest.squishinessFraction = 0.3f
 
                 sysuiStatusBarStateController.setState(StatusBarState.SHADE)
-                Snapshot.sendApplyNotifications()
                 runCurrent()
                 assertThat(underTest.qsMediaHost.squishFraction).isWithin(epsilon).of(0.3f)
 
                 sysuiStatusBarStateController.setState(StatusBarState.KEYGUARD)
                 runCurrent()
-                Snapshot.sendApplyNotifications()
-                runCurrent()
                 assertThat(underTest.qsMediaHost.squishFraction).isWithin(epsilon).of(1f)
 
                 sysuiStatusBarStateController.setState(StatusBarState.SHADE_LOCKED)
                 runCurrent()
-                Snapshot.sendApplyNotifications()
-                runCurrent()
                 assertThat(underTest.qsMediaHost.squishFraction).isWithin(epsilon).of(1f)
             }
         }
@@ -446,8 +423,6 @@
                 setMediaState(ACTIVE_MEDIA)
 
                 setConfigurationForMediaInRow(false)
-                Snapshot.sendApplyNotifications()
-                runCurrent()
 
                 assertThat(underTest.qqsMediaHost.disappearParameters)
                     .isEqualTo(disappearParamsColumn)
@@ -455,8 +430,6 @@
                     .isEqualTo(disappearParamsColumn)
 
                 setConfigurationForMediaInRow(true)
-                Snapshot.sendApplyNotifications()
-                runCurrent()
 
                 assertThat(underTest.qqsMediaHost.disappearParameters).isEqualTo(disappearParamsRow)
                 assertThat(underTest.qsMediaHost.disappearParameters).isEqualTo(disappearParamsRow)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt
index 4acf3ee..645efae 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt
@@ -27,7 +27,7 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class MutableSelectionStateTest : SysuiTestCase() {
-    private val underTest = MutableSelectionState({}, {})
+    private val underTest = MutableSelectionState()
 
     @Test
     fun selectTile_isCorrectlySelected() {
@@ -48,120 +48,6 @@
         assertThat(underTest.selection?.manual).isFalse()
     }
 
-    @Test
-    fun startResize_createsResizingState() {
-        assertThat(underTest.resizingState).isNull()
-
-        // Resizing starts but no tile is selected
-        underTest.onResizingDragStart(TileWidths(0, 0, 1))
-        assertThat(underTest.resizingState).isNull()
-
-        // Resizing starts with a selected tile
-        underTest.select(TEST_SPEC, manual = true)
-        underTest.onResizingDragStart(TileWidths(0, 0, 1))
-
-        assertThat(underTest.resizingState).isNotNull()
-    }
-
-    @Test
-    fun endResize_clearsResizingState() {
-        val spec = TileSpec.create("testSpec")
-
-        // Resizing starts with a selected tile
-        underTest.select(spec, manual = true)
-        underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10))
-        assertThat(underTest.resizingState).isNotNull()
-
-        underTest.onResizingDragEnd()
-        assertThat(underTest.resizingState).isNull()
-    }
-
-    @Test
-    fun unselect_clearsResizingState() {
-        // Resizing starts with a selected tile
-        underTest.select(TEST_SPEC, manual = true)
-        underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10))
-        assertThat(underTest.resizingState).isNotNull()
-
-        underTest.unSelect()
-        assertThat(underTest.resizingState).isNull()
-    }
-
-    @Test
-    fun onResizingDrag_updatesResizingState() {
-        // Resizing starts with a selected tile
-        underTest.select(TEST_SPEC, manual = true)
-        underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10))
-        assertThat(underTest.resizingState).isNotNull()
-
-        underTest.onResizingDrag(5f)
-        assertThat(underTest.resizingState?.width).isEqualTo(5)
-
-        underTest.onResizingDrag(2f)
-        assertThat(underTest.resizingState?.width).isEqualTo(7)
-
-        underTest.onResizingDrag(-6f)
-        assertThat(underTest.resizingState?.width).isEqualTo(1)
-    }
-
-    @Test
-    fun onResizingDrag_receivesResizeCallback() {
-        var resized = false
-        val onResize: (TileSpec) -> Unit = {
-            assertThat(it).isEqualTo(TEST_SPEC)
-            resized = !resized
-        }
-        val underTest = MutableSelectionState(onResize = onResize, {})
-
-        // Resizing starts with a selected tile
-        underTest.select(TEST_SPEC, true)
-        underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10))
-        assertThat(underTest.resizingState).isNotNull()
-
-        // Drag under the threshold
-        underTest.onResizingDrag(1f)
-        assertThat(resized).isFalse()
-
-        // Drag over the threshold
-        underTest.onResizingDrag(5f)
-        assertThat(resized).isTrue()
-
-        // Drag back under the threshold
-        underTest.onResizingDrag(-5f)
-        assertThat(resized).isFalse()
-    }
-
-    @Test
-    fun onResizingEnded_receivesResizeEndCallback() {
-        var resizeEnded = false
-        val onResizeEnd: (TileSpec) -> Unit = { resizeEnded = true }
-        val underTest = MutableSelectionState({}, onResizeEnd = onResizeEnd)
-
-        // Resizing starts with a selected tile
-        underTest.select(TEST_SPEC, true)
-        underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10))
-
-        underTest.onResizingDragEnd()
-        assertThat(resizeEnded).isTrue()
-    }
-
-    @Test
-    fun onResizingEnded_setsSelectionAutomatically() {
-        val underTest = MutableSelectionState({}, {})
-
-        // Resizing starts with a selected tile
-        underTest.select(TEST_SPEC, manual = true)
-        underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10))
-
-        // Assert the selection was manual
-        assertThat(underTest.selection?.manual).isTrue()
-
-        underTest.onResizingDragEnd()
-
-        // Assert the selection is no longer manual due to the resizing
-        assertThat(underTest.selection?.manual).isFalse()
-    }
-
     companion object {
         private val TEST_SPEC = TileSpec.create("testSpec")
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingStateTest.kt
index 6e66783..2206f4d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingStateTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingStateTest.kt
@@ -19,7 +19,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.qs.pipeline.shared.TileSpec
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -27,36 +29,32 @@
 @RunWith(AndroidJUnit4::class)
 class ResizingStateTest : SysuiTestCase() {
 
+    private val underTest =
+        ResizingState(TileSpec.create("a"), startsAsIcon = true).apply { updateAnchors(10f, 20f) }
+
     @Test
-    fun drag_updatesStateCorrectly() {
-        var resized = false
-        val underTest =
-            ResizingState(TileWidths(base = 0, min = 0, max = 10)) { resized = !resized }
-
-        assertThat(underTest.width).isEqualTo(0)
-
-        underTest.onDrag(2f)
-        assertThat(underTest.width).isEqualTo(2)
-
-        underTest.onDrag(1f)
-        assertThat(underTest.width).isEqualTo(3)
-        assertThat(resized).isTrue()
-
-        underTest.onDrag(-1f)
-        assertThat(underTest.width).isEqualTo(2)
-        assertThat(resized).isFalse()
+    fun newResizingState_setInitialValueCorrectly() {
+        assertThat(underTest.anchoredDraggableState.currentValue).isEqualTo(QSDragAnchor.Icon)
     }
 
     @Test
-    fun dragOutOfBounds_isClampedCorrectly() {
-        val underTest = ResizingState(TileWidths(base = 0, min = 0, max = 10)) {}
+    fun updateAnchors_setBoundsCorrectly() {
+        assertThat(underTest.bounds).isEqualTo(10f to 20f)
+    }
 
-        assertThat(underTest.width).isEqualTo(0)
+    @Test
+    fun dragOverThreshold_resizesToLarge() = runTest {
+        underTest.anchoredDraggableState.anchoredDrag { dragTo(16f) }
 
-        underTest.onDrag(100f)
-        assertThat(underTest.width).isEqualTo(10)
+        assertThat(underTest.temporaryResizeOperation.spec).isEqualTo(TileSpec.create("a"))
+        assertThat(underTest.temporaryResizeOperation.toIcon).isFalse()
+    }
 
-        underTest.onDrag(-200f)
-        assertThat(underTest.width).isEqualTo(0)
+    @Test
+    fun dragUnderThreshold_staysIcon() = runTest {
+        underTest.anchoredDraggableState.anchoredDrag { dragTo(12f) }
+
+        assertThat(underTest.temporaryResizeOperation.spec).isEqualTo(TileSpec.create("a"))
+        assertThat(underTest.temporaryResizeOperation.toIcon).isTrue()
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelTest.kt
new file mode 100644
index 0000000..98770c7
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelTest.kt
@@ -0,0 +1,94 @@
+/*
+ * 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.qs.panels.ui.viewmodel
+
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.qs.FakeQSTile
+import com.android.systemui.qs.pipeline.data.repository.tileSpecRepository
+import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+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
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class DetailsViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private lateinit var underTest: DetailsViewModel
+    private val spec = TileSpec.create("internet")
+    private val specNoDetails = TileSpec.create("NoDetailsTile")
+
+    @Before
+    fun setUp() {
+        underTest = kosmos.detailsViewModel
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    fun changeTileDetailsViewModel() = with(kosmos) {
+        testScope.runTest {
+            val specs = listOf(
+                spec,
+                specNoDetails,
+            )
+            tileSpecRepository.setTiles(0, specs)
+            runCurrent()
+
+            val tiles = currentTilesInteractor.currentTiles.value
+
+            assertThat(currentTilesInteractor.currentTilesSpecs.size).isEqualTo(2)
+            assertThat(tiles!![1].spec).isEqualTo(specNoDetails)
+            (tiles!![1].tile as FakeQSTile).hasDetailsViewModel = false
+
+            assertThat(underTest.activeTileDetails).isNull()
+
+            // Click on the tile who has the `spec`.
+            assertThat(underTest.onTileClicked(spec)).isTrue()
+            assertThat(underTest.activeTileDetails).isNotNull()
+            assertThat(underTest.activeTileDetails?.getTitle()).isEqualTo("internet")
+
+            // Click on a tile who dose not have a valid spec.
+            assertThat(underTest.onTileClicked(null)).isFalse()
+            assertThat(underTest.activeTileDetails).isNull()
+
+            // Click again on the tile who has the `spec`.
+            assertThat(underTest.onTileClicked(spec)).isTrue()
+            assertThat(underTest.activeTileDetails).isNotNull()
+            assertThat(underTest.activeTileDetails?.getTitle()).isEqualTo("internet")
+
+            // Click on a tile who dose not have a detailed view.
+            assertThat(underTest.onTileClicked(specNoDetails)).isFalse()
+            assertThat(underTest.activeTileDetails).isNull()
+
+            underTest.closeDetailedView()
+            assertThat(underTest.activeTileDetails).isNull()
+
+            assertThat(underTest.onTileClicked(null)).isFalse()
+        }
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelTest.kt
new file mode 100644
index 0000000..f2bfd72
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelTest.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.qs.panels.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.fakeFalsingManager
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runCurrent
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class EditModeButtonViewModelTest : SysuiTestCase() {
+    val kosmos = testKosmos()
+
+    val underTest = kosmos.editModeButtonViewModelFactory.create()
+
+    @Test
+    fun falsingFalseTap_editModeDoesntStart() =
+        kosmos.runTest {
+            val isEditing by collectLastValue(editModeViewModel.isEditing)
+
+            fakeFalsingManager.setFalseTap(true)
+
+            underTest.onButtonClick()
+            runCurrent()
+
+            assertThat(isEditing).isFalse()
+        }
+
+    @Test
+    fun falsingNotFalseTap_editModeStarted() =
+        kosmos.runTest {
+            val isEditing by collectLastValue(editModeViewModel.isEditing)
+
+            fakeFalsingManager.setFalseTap(false)
+
+            underTest.onButtonClick()
+            runCurrent()
+
+            assertThat(isEditing).isTrue()
+        }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
index 8995f46..165ff7b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
@@ -691,6 +691,32 @@
             verify(logger, never()).logTileUserChanged(TileSpec.create("a"), 0)
         }
 
+
+    @Test
+    fun getTileDetails() =
+        testScope.runTest(USER_INFO_0) {
+            val tiles by collectLastValue(underTest.currentTiles)
+            val tileA = TileSpec.create("a")
+            val tileB = TileSpec.create("b")
+            val tileNoDetails = TileSpec.create("NoDetails")
+
+            val specs = listOf(tileA, tileB, tileNoDetails)
+
+            assertThat(tiles!!.isEmpty()).isTrue()
+
+            tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+            assertThat(tiles!!.size).isEqualTo(3)
+
+            // The third tile doesn't have a details view.
+            assertThat(tiles!![2].spec).isEqualTo(tileNoDetails)
+            (tiles!![2].tile as FakeQSTile).hasDetailsViewModel = false
+
+            assertThat(tiles!![0].tile.detailsViewModel.getTitle()).isEqualTo("a")
+            assertThat(tiles!![1].tile.detailsViewModel.getTitle()).isEqualTo("b")
+            assertThat(tiles!![2].tile.detailsViewModel).isNull()
+        }
+
+
     private fun QSTile.State.fillIn(state: Int, label: CharSequence, secondaryLabel: CharSequence) {
         this.state = state
         this.label = label
@@ -770,7 +796,7 @@
         private val USER_INFO_0 = UserInfo().apply { id = 0 }
         private val USER_INFO_1 = UserInfo().apply { id = 1 }
 
-        private val VALID_TILES = setOf("a", "b", "c", "d", "e")
+        private val VALID_TILES = setOf("a", "b", "c", "d", "e", "NoDetails")
         private val TEST_COMPONENT = ComponentName("pkg", "cls")
         private val CUSTOM_TILE_SPEC = TileSpec.Companion.create(TEST_COMPONENT)
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractorTest.kt
new file mode 100644
index 0000000..08225a77
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractorTest.kt
@@ -0,0 +1,145 @@
+/*
+ * 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.domain.interactor
+
+import android.app.StatusBarManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.launch
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DisabledContentInteractorTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+
+    private val underTest = kosmos.disabledContentInteractor
+
+    @Test
+    fun isDisabled_notificationsShade() =
+        kosmos.runTest {
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_NONE)
+            assertThat(underTest.isDisabled(Overlays.NotificationsShade)).isFalse()
+
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_NOTIFICATION_SHADE)
+            assertThat(underTest.isDisabled(Overlays.NotificationsShade)).isTrue()
+        }
+
+    @Test
+    fun isDisabled_qsShade() =
+        kosmos.runTest {
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_NONE)
+            assertThat(underTest.isDisabled(Overlays.QuickSettingsShade)).isFalse()
+
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_QUICK_SETTINGS)
+            assertThat(underTest.isDisabled(Overlays.QuickSettingsShade)).isTrue()
+        }
+
+    @Test
+    fun repeatWhenDisabled() =
+        kosmos.runTest {
+            var notificationDisabledCount = 0
+            applicationCoroutineScope.launch {
+                underTest.repeatWhenDisabled(Overlays.NotificationsShade) {
+                    notificationDisabledCount++
+                }
+            }
+            var qsDisabledCount = 0
+            applicationCoroutineScope.launch {
+                underTest.repeatWhenDisabled(Overlays.QuickSettingsShade) { qsDisabledCount++ }
+            }
+
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_QUICK_SETTINGS)
+            assertThat(notificationDisabledCount).isEqualTo(0)
+            assertThat(qsDisabledCount).isEqualTo(1)
+
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(
+                    disable2 =
+                        StatusBarManager.DISABLE2_NOTIFICATION_SHADE or
+                            StatusBarManager.DISABLE2_QUICK_SETTINGS
+                )
+            assertThat(notificationDisabledCount).isEqualTo(1)
+            assertThat(qsDisabledCount).isEqualTo(1)
+
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_NOTIFICATION_SHADE)
+            assertThat(notificationDisabledCount).isEqualTo(1)
+            assertThat(qsDisabledCount).isEqualTo(1)
+
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_QUICK_SETTINGS)
+            assertThat(notificationDisabledCount).isEqualTo(1)
+            assertThat(qsDisabledCount).isEqualTo(2)
+        }
+
+    @Test
+    fun filteredUserActions() =
+        kosmos.runTest {
+            val map =
+                mapOf<UserAction, UserActionResult>(
+                    Swipe.Up to UserActionResult.ShowOverlay(Overlays.NotificationsShade),
+                    Swipe.Down to UserActionResult.ShowOverlay(Overlays.QuickSettingsShade),
+                )
+            val unfiltered = MutableStateFlow(map)
+            val filtered by collectLastValue(underTest.filteredUserActions(unfiltered))
+            assertThat(filtered).isEqualTo(map)
+
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_NOTIFICATION_SHADE)
+            assertThat(filtered)
+                .isEqualTo(
+                    mapOf(Swipe.Down to UserActionResult.ShowOverlay(Overlays.QuickSettingsShade))
+                )
+
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_QUICK_SETTINGS)
+            assertThat(filtered)
+                .isEqualTo(
+                    mapOf(Swipe.Up to UserActionResult.ShowOverlay(Overlays.NotificationsShade))
+                )
+
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(
+                    disable2 =
+                        StatusBarManager.DISABLE2_NOTIFICATION_SHADE or
+                            StatusBarManager.DISABLE2_QUICK_SETTINGS
+                )
+            assertThat(filtered).isEqualTo(emptyMap<UserAction, UserActionResult>())
+        }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index 7fe3d8d..48edded 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -18,6 +18,7 @@
 
 package com.android.systemui.scene.domain.interactor
 
+import android.app.StatusBarManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.compose.animation.scene.ObservableTransitionState
@@ -30,6 +31,8 @@
 import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
 import com.android.systemui.keyguard.domain.interactor.keyguardEnabledInteractor
 import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.scene.data.repository.Idle
 import com.android.systemui.scene.data.repository.Transition
@@ -43,6 +46,8 @@
 import com.android.systemui.scene.shared.model.SceneFamilies
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.shared.model.fakeSceneDataSource
+import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -523,4 +528,51 @@
 
             assertThat(currentScene).isEqualTo(Scenes.Gone)
         }
+
+    @Test
+    fun showOverlay_overlayDisabled_doesNothing() =
+        kosmos.runTest {
+            val currentOverlays by collectLastValue(underTest.currentOverlays)
+            val disabledOverlay = Overlays.QuickSettingsShade
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_QUICK_SETTINGS)
+            assertThat(disabledContentInteractor.isDisabled(disabledOverlay)).isTrue()
+            assertThat(currentOverlays).doesNotContain(disabledOverlay)
+
+            underTest.showOverlay(disabledOverlay, "reason")
+
+            assertThat(currentOverlays).doesNotContain(disabledOverlay)
+        }
+
+    @Test
+    fun replaceOverlay_withDisabledOverlay_doesNothing() =
+        kosmos.runTest {
+            val currentOverlays by collectLastValue(underTest.currentOverlays)
+            val showingOverlay = Overlays.NotificationsShade
+            underTest.showOverlay(showingOverlay, "reason")
+            assertThat(currentOverlays).isEqualTo(setOf(showingOverlay))
+            val disabledOverlay = Overlays.QuickSettingsShade
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_QUICK_SETTINGS)
+            assertThat(disabledContentInteractor.isDisabled(disabledOverlay)).isTrue()
+
+            underTest.replaceOverlay(showingOverlay, disabledOverlay, "reason")
+
+            assertThat(currentOverlays).isEqualTo(setOf(showingOverlay))
+        }
+
+    @Test
+    fun changeScene_toDisabledScene_doesNothing() =
+        kosmos.runTest {
+            val currentScene by collectLastValue(underTest.currentScene)
+            val disabledScene = Scenes.Shade
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_NOTIFICATION_SHADE)
+            assertThat(disabledContentInteractor.isDisabled(disabledScene)).isTrue()
+            assertThat(currentScene).isNotEqualTo(disabledScene)
+
+            underTest.changeScene(disabledScene, "reason")
+
+            assertThat(currentScene).isNotEqualTo(disabledScene)
+        }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt
index db2297c..3d014b6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt
@@ -35,9 +35,9 @@
 import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
 import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs
 import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.notification.init.NotificationsController
 import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index cca847e..79bb0c4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -81,6 +81,9 @@
 import com.android.systemui.keyguard.shared.model.FailFingerprintAuthenticationStatus
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runCurrent
+import com.android.systemui.kosmos.runTest
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.model.sysUiState
 import com.android.systemui.power.data.repository.fakePowerRepository
@@ -101,6 +104,8 @@
 import com.android.systemui.shade.shared.flag.DualShade
 import com.android.systemui.shared.system.QuickStepContract
 import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
 import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor
 import com.android.systemui.statusbar.notification.data.repository.FakeHeadsUpRowRepository
 import com.android.systemui.statusbar.notification.data.repository.HeadsUpRowRepository
@@ -2673,6 +2678,25 @@
             assertThat(isAlternateBouncerVisible).isFalse()
         }
 
+    @Test
+    fun handleDisableFlags() =
+        kosmos.runTest {
+            underTest.start()
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+            sceneInteractor.changeScene(Scenes.Shade, "reason")
+            sceneInteractor.showOverlay(Overlays.NotificationsShade, "reason")
+            assertThat(currentScene).isEqualTo(Scenes.Shade)
+            assertThat(currentOverlays).contains(Overlays.NotificationsShade)
+
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(disable2 = StatusBarManager.DISABLE2_NOTIFICATION_SHADE)
+            runCurrent()
+
+            assertThat(currentScene).isNotEqualTo(Scenes.Shade)
+            assertThat(currentOverlays).isEmpty()
+        }
+
     private fun TestScope.emulateSceneTransition(
         transitionStateFlow: MutableStateFlow<ObservableTransitionState>,
         toScene: SceneKey,
@@ -2837,9 +2861,7 @@
         )
 
     private fun fakeHeadsUpRowRepository(key: String, isPinned: Boolean) =
-        FakeHeadsUpRowRepository(key = key, elementKey = Any()).apply {
-            this.isPinned.value = isPinned
-        }
+        FakeHeadsUpRowRepository(key = key, elementKey = Any(), isPinned = isPinned)
 
     private fun setFingerprintSensorType(fingerprintSensorType: FingerprintSensorType) {
         kosmos.fingerprintPropertyRepository.setProperties(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index ed31f36..0d8d57e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -150,7 +150,7 @@
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.ConversationNotificationManager;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinatorLogger;
 import com.android.systemui.statusbar.notification.data.repository.NotificationsKeyguardViewStateRepository;
@@ -178,12 +178,12 @@
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
+import com.android.systemui.statusbar.phone.ShadeTouchableRegionManager;
 import com.android.systemui.statusbar.phone.TapAgainViewController;
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController;
@@ -245,7 +245,7 @@
     @Mock protected NotificationPanelView mView;
     @Mock protected LayoutInflater mLayoutInflater;
     @Mock protected DynamicPrivacyController mDynamicPrivacyController;
-    @Mock protected StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
+    @Mock protected ShadeTouchableRegionManager mShadeTouchableRegionManager;
     @Mock protected KeyguardStateController mKeyguardStateController;
     @Mock protected DozeLog mDozeLog;
     private final ShadeLogger mShadeLog = new ShadeLogger(logcatLogBuffer());
@@ -703,7 +703,7 @@
                 mMetricsLogger,
                 mShadeLog,
                 mConfigurationController,
-                () -> flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
+                () -> flingAnimationUtilsBuilder, mShadeTouchableRegionManager,
                 mConversationNotificationManager, mMediaHierarchyManager,
                 mStatusBarKeyguardViewManager,
                 mGutsManager,
@@ -819,7 +819,7 @@
                 mLockscreenShadeTransitionController,
                 mNotificationShadeDepthController,
                 mShadeHeaderController,
-                mStatusBarTouchableRegionManager,
+                mShadeTouchableRegionManager,
                 () -> mStatusBarLongPressGestureDetector,
                 mKeyguardStateController,
                 mKeyguardBypassController,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
index 61d4c99..b58c13c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
@@ -71,8 +71,8 @@
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
 import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.ShadeTouchableRegionManager;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
@@ -125,7 +125,7 @@
     @Mock protected LockscreenShadeTransitionController mLockscreenShadeTransitionController;
     @Mock protected NotificationShadeDepthController mNotificationShadeDepthController;
     @Mock protected ShadeHeaderController mShadeHeaderController;
-    @Mock protected StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
+    @Mock protected ShadeTouchableRegionManager mShadeTouchableRegionManager;
     @Mock protected StatusBarLongPressGestureDetector mStatusBarLongPressGestureDetector;
     @Mock protected DozeParameters mDozeParameters;
     @Mock protected KeyguardStateController mKeyguardStateController;
@@ -250,7 +250,7 @@
                 mLockscreenShadeTransitionController,
                 mNotificationShadeDepthController,
                 mShadeHeaderController,
-                mStatusBarTouchableRegionManager,
+                mShadeTouchableRegionManager,
                 () -> mStatusBarLongPressGestureDetector,
                 mKeyguardStateController,
                 mKeyguardBypassController,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
index 0f476d0..c6ce581 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
@@ -36,10 +36,10 @@
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.statusbar.window.StatusBarWindowController
 import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt
new file mode 100644
index 0000000..0966759
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt
@@ -0,0 +1,89 @@
+/*
+ * 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.shade.data.repository
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.shade.display.ShadeDisplayPolicy
+import com.android.systemui.shade.display.SpecificDisplayIdPolicy
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ShadeDisplaysRepositoryTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private val defaultPolicy = SpecificDisplayIdPolicy(0)
+
+    private val shadeDisplaysRepository =
+        ShadeDisplaysRepositoryImpl(defaultPolicy, testScope.backgroundScope)
+
+    @Test
+    fun policy_changing_propagatedFromTheLatestPolicy() =
+        testScope.runTest {
+            val displayIds by collectValues(shadeDisplaysRepository.displayId)
+            val policy1 = MutablePolicy()
+            val policy2 = MutablePolicy()
+
+            assertThat(displayIds).containsExactly(0)
+
+            shadeDisplaysRepository.policy.value = policy1
+
+            policy1.sendDisplayId(1)
+
+            assertThat(displayIds).containsExactly(0, 1)
+
+            policy1.sendDisplayId(2)
+
+            assertThat(displayIds).containsExactly(0, 1, 2)
+
+            shadeDisplaysRepository.policy.value = policy2
+
+            assertThat(displayIds).containsExactly(0, 1, 2, 0)
+
+            policy1.sendDisplayId(4)
+
+            // Changes to the first policy don't affect the output now
+            assertThat(displayIds).containsExactly(0, 1, 2, 0)
+
+            policy2.sendDisplayId(5)
+
+            assertThat(displayIds).containsExactly(0, 1, 2, 0, 5)
+        }
+
+    private class MutablePolicy : ShadeDisplayPolicy {
+        fun sendDisplayId(id: Int) {
+            _displayId.value = id
+        }
+
+        private val _displayId = MutableStateFlow(0)
+        override val name: String
+            get() = "mutable_policy"
+
+        override val displayId: StateFlow<Int>
+            get() = _displayId
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt
index af01547..d584dc9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt
@@ -23,12 +23,17 @@
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.display.data.repository.displayRepository
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
 import com.android.systemui.shade.ShadePrimaryDisplayCommand
+import com.android.systemui.shade.display.ShadeDisplayPolicy
 import com.android.systemui.statusbar.commandline.commandRegistry
 import com.android.systemui.testKosmos
+import com.google.common.truth.StringSubject
 import com.google.common.truth.Truth.assertThat
 import java.io.PrintWriter
 import java.io.StringWriter
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
@@ -37,15 +42,26 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class ShadePrimaryDisplayCommandTest : SysuiTestCase() {
-    private val kosmos = testKosmos()
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
     private val testScope = kosmos.testScope
     private val commandRegistry = kosmos.commandRegistry
     private val displayRepository = kosmos.displayRepository
-    private val shadeDisplaysRepository = ShadeDisplaysRepositoryImpl()
+    private val defaultPolicy = kosmos.defaultShadeDisplayPolicy
+    private val policy1 = makePolicy("policy_1")
+    private val shadeDisplaysRepository = kosmos.shadeDisplaysRepository
     private val pw = PrintWriter(StringWriter())
 
+    private val policies =
+        setOf(defaultPolicy, policy1, makePolicy("policy_2"), makePolicy("policy_3"))
+
     private val underTest =
-        ShadePrimaryDisplayCommand(commandRegistry, displayRepository, shadeDisplaysRepository)
+        ShadePrimaryDisplayCommand(
+            commandRegistry,
+            displayRepository,
+            shadeDisplaysRepository,
+            policies,
+            defaultPolicy,
+        )
 
     @Before
     fun setUp() {
@@ -96,4 +112,41 @@
 
             assertThat(displayId).isEqualTo(newDisplayId)
         }
+
+    @Test
+    fun policies_listsAllPolicies() =
+        testScope.runTest {
+            val stringWriter = StringWriter()
+            commandRegistry.onShellCommand(
+                PrintWriter(stringWriter),
+                arrayOf("shade_display_override", "policies"),
+            )
+            val result = stringWriter.toString()
+
+            assertThat(result).containsAllIn(policies.map { it.name })
+        }
+
+    @Test
+    fun policies_setsSpecificPolicy() =
+        testScope.runTest {
+            val policy by collectLastValue(shadeDisplaysRepository.policy)
+
+            commandRegistry.onShellCommand(pw, arrayOf("shade_display_override", policy1.name))
+
+            assertThat(policy!!.name).isEqualTo(policy1.name)
+        }
+
+    private fun makePolicy(policyName: String): ShadeDisplayPolicy {
+        return object : ShadeDisplayPolicy {
+            override val name: String
+                get() = policyName
+
+            override val displayId: StateFlow<Int>
+                get() = MutableStateFlow(0)
+        }
+    }
+}
+
+private fun StringSubject.containsAllIn(strings: List<String>) {
+    strings.forEach { contains(it) }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/AnyExternalShadeDisplayPolicyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/AnyExternalShadeDisplayPolicyTest.kt
new file mode 100644
index 0000000..4d4efd1
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/AnyExternalShadeDisplayPolicyTest.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.shade.display
+
+import android.view.Display
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.display.data.repository.display
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.test.runTest
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AnyExternalShadeDisplayPolicyTest : SysuiTestCase() {
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+    private val testScope = kosmos.testScope
+    private val displayRepository = kosmos.displayRepository
+    val underTest = AnyExternalShadeDisplayPolicy(displayRepository, testScope.backgroundScope)
+
+    @Test
+    fun displayId_ignoresUnwantedTypes() =
+        testScope.runTest {
+            val displayId by collectLastValue(underTest.displayId)
+
+            displayRepository.addDisplays(
+                display(id = 0, type = Display.TYPE_INTERNAL),
+                display(id = 1, type = Display.TYPE_UNKNOWN),
+                display(id = 2, type = Display.TYPE_VIRTUAL),
+                display(id = 3, type = Display.TYPE_EXTERNAL),
+            )
+
+            assertThat(displayId).isEqualTo(3)
+        }
+
+    @Test
+    fun displayId_onceRemoved_goesToNextDisplay() =
+        testScope.runTest {
+            val displayId by collectLastValue(underTest.displayId)
+
+            displayRepository.addDisplays(
+                display(id = 0, type = Display.TYPE_INTERNAL),
+                display(id = 2, type = Display.TYPE_EXTERNAL),
+                display(id = 3, type = Display.TYPE_EXTERNAL),
+            )
+
+            assertThat(displayId).isEqualTo(2)
+
+            displayRepository.removeDisplay(2)
+
+            assertThat(displayId).isEqualTo(3)
+        }
+
+    @Test
+    fun displayId_onlyDefaultDisplay_defaultDisplay() =
+        testScope.runTest {
+            val displayId by collectLastValue(underTest.displayId)
+
+            displayRepository.addDisplays(display(id = 0, type = Display.TYPE_INTERNAL))
+
+            assertThat(displayId).isEqualTo(0)
+        }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt
index 8ef1e56..982c51b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt
@@ -29,7 +29,7 @@
 import com.android.systemui.display.shared.model.DisplayWindowProperties
 import com.android.systemui.scene.ui.view.WindowRootView
 import com.android.systemui.shade.data.repository.FakeShadeDisplayRepository
-import com.android.systemui.statusbar.phone.ConfigurationForwarder
+import java.util.Optional
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
@@ -37,6 +37,7 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Mockito.inOrder
 import org.mockito.Mockito.verify
 import org.mockito.kotlin.any
 import org.mockito.kotlin.eq
@@ -51,26 +52,22 @@
 
     private val shadeRootview = mock<WindowRootView>()
     private val positionRepository = FakeShadeDisplayRepository()
-    private val defaultContext = mock<Context>()
-    private val secondaryContext = mock<Context>()
+    private val shadeContext = mock<Context>()
     private val contextStore = FakeDisplayWindowPropertiesRepository()
     private val testScope = TestScope(UnconfinedTestDispatcher())
-    private val configurationForwarder = mock<ConfigurationForwarder>()
-    private val defaultWm = mock<WindowManager>()
-    private val secondaryWm = mock<WindowManager>()
+    private val shadeWm = mock<WindowManager>()
     private val resources = mock<Resources>()
     private val configuration = mock<Configuration>()
     private val display = mock<Display>()
 
     private val interactor =
         ShadeDisplaysInteractor(
-            shadeRootview,
+            Optional.of(shadeRootview),
             positionRepository,
-            defaultContext,
-            contextStore,
-            testScope,
-            configurationForwarder,
-            testScope.coroutineContext,
+            shadeContext,
+            shadeWm,
+            testScope.backgroundScope,
+            testScope.backgroundScope.coroutineContext,
         )
 
     @Before
@@ -79,30 +76,16 @@
         whenever(display.displayId).thenReturn(0)
 
         whenever(resources.configuration).thenReturn(configuration)
-        whenever(resources.configuration).thenReturn(configuration)
 
-        whenever(defaultContext.displayId).thenReturn(0)
-        whenever(defaultContext.getSystemService(any())).thenReturn(defaultWm)
-        whenever(defaultContext.resources).thenReturn(resources)
+        whenever(shadeContext.displayId).thenReturn(0)
+        whenever(shadeContext.getSystemService(any())).thenReturn(shadeWm)
+        whenever(shadeContext.resources).thenReturn(resources)
         contextStore.insert(
             DisplayWindowProperties(
                 displayId = 0,
                 windowType = TYPE_NOTIFICATION_SHADE,
-                context = defaultContext,
-                windowManager = defaultWm,
-                layoutInflater = mock(),
-            )
-        )
-
-        whenever(secondaryContext.displayId).thenReturn(1)
-        whenever(secondaryContext.getSystemService(any())).thenReturn(secondaryWm)
-        whenever(secondaryContext.resources).thenReturn(resources)
-        contextStore.insert(
-            DisplayWindowProperties(
-                displayId = 1,
-                windowType = TYPE_NOTIFICATION_SHADE,
-                context = secondaryContext,
-                windowManager = secondaryWm,
+                context = shadeContext,
+                windowManager = shadeWm,
                 layoutInflater = mock(),
             )
         )
@@ -115,8 +98,7 @@
         interactor.start()
         testScope.advanceUntilIdle()
 
-        verifyNoMoreInteractions(defaultWm)
-        verifyNoMoreInteractions(secondaryWm)
+        verifyNoMoreInteractions(shadeWm)
     }
 
     @Test
@@ -124,10 +106,11 @@
         whenever(display.displayId).thenReturn(0)
         positionRepository.setDisplayId(1)
         interactor.start()
-        testScope.advanceUntilIdle()
 
-        verify(defaultWm).removeView(eq(shadeRootview))
-        verify(secondaryWm).addView(eq(shadeRootview), any())
+        inOrder(shadeWm).apply {
+            verify(shadeWm).removeView(eq(shadeRootview))
+            verify(shadeWm).addView(eq(shadeRootview), any())
+        }
     }
 
     @Test
@@ -135,25 +118,12 @@
         whenever(display.displayId).thenReturn(0)
         positionRepository.setDisplayId(0)
         interactor.start()
-        testScope.advanceUntilIdle()
 
         positionRepository.setDisplayId(1)
-        testScope.advanceUntilIdle()
 
-        verify(defaultWm).removeView(eq(shadeRootview))
-        verify(secondaryWm).addView(eq(shadeRootview), any())
-    }
-
-    @Test
-    fun start_shadePositionChanges_newConfigPropagated() {
-        whenever(display.displayId).thenReturn(0)
-        positionRepository.setDisplayId(0)
-        interactor.start()
-        testScope.advanceUntilIdle()
-
-        positionRepository.setDisplayId(1)
-        testScope.advanceUntilIdle()
-
-        verify(configurationForwarder).onConfigurationChanged(eq(configuration))
+        inOrder(shadeWm).apply {
+            verify(shadeWm).removeView(eq(shadeRootview))
+            verify(shadeWm).addView(eq(shadeRootview), any())
+        }
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModelTest.kt
index 558606f..a9d5790 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModelTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.shade.ui.viewmodel
 
+import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
 import android.platform.test.annotations.DisableFlags
 import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -42,6 +43,7 @@
 import com.android.systemui.shade.data.repository.shadeRepository
 import com.android.systemui.shade.shared.flag.DualShade
 import com.android.systemui.shade.shared.model.ShadeMode
+import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
 import com.android.systemui.testKosmos
 import com.android.systemui.unfold.fakeUnfoldTransitionProgressProvider
 import com.google.common.truth.Truth.assertThat
@@ -49,6 +51,7 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.update
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
@@ -158,10 +161,7 @@
                         underTest.unfoldTranslationX(isOnStartSide = true),
                         underTest.unfoldTranslationX(isOnStartSide = false),
                     ) { start, end ->
-                        Translations(
-                            start = start,
-                            end = end,
-                        )
+                        Translations(start = start, end = end)
                     }
                 )
 
@@ -186,6 +186,20 @@
             assertThat(translations?.end).isEqualTo(-0f)
         }
 
+    @Test
+    fun disable2QuickSettings_isQsEnabledIsFalse() =
+        testScope.runTest {
+            val isQsEnabled by collectLastValue(underTest.isQsEnabled)
+            assertThat(isQsEnabled).isTrue()
+
+            kosmos.fakeDisableFlagsRepository.disableFlags.update {
+                it.copy(disable2 = DISABLE2_QUICK_SETTINGS)
+            }
+            runCurrent()
+
+            assertThat(isQsEnabled).isFalse()
+        }
+
     private fun prepareConfiguration(): Int {
         val configuration = context.resources.configuration
         configuration.setLayoutDirection(Locale.US)
@@ -193,7 +207,7 @@
         val maxTranslation = 10
         kosmos.fakeConfigurationRepository.setDimensionPixelSize(
             R.dimen.notification_side_paddings,
-            maxTranslation
+            maxTranslation,
         )
         return maxTranslation
     }
@@ -224,8 +238,5 @@
         runCurrent()
     }
 
-    private data class Translations(
-        val start: Float,
-        val end: Float,
-    )
+    private data class Translations(val start: Float, val end: Float)
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginActionManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginActionManagerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginActionManagerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginActionManagerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index da0029f..32a9f54 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -48,7 +48,6 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyObject;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
@@ -1633,7 +1632,7 @@
         } else {
             verify(mRotateTextViewController).hideIndication(type);
             verify(mRotateTextViewController, never()).updateIndication(eq(type),
-                    anyObject(), anyBoolean());
+                    any(), anyBoolean());
         }
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
index 9907740..cd66ef3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
@@ -26,10 +26,10 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.notification.row.ExpandableView
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.util.mockito.mock
 import kotlinx.coroutines.flow.MutableStateFlow
 import org.junit.Before
@@ -76,7 +76,7 @@
                 falsingManager,
                 shadeInteractor,
                 lockscreenShadeTransitionController,
-                dumpManager
+                dumpManager,
             )
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt
new file mode 100644
index 0000000..7fed47a
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt
@@ -0,0 +1,207 @@
+/*
+ * 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.statusbar.chips.notification.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.activity.data.repository.activityManagerRepository
+import com.android.systemui.activity.data.repository.fake
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SingleNotificationChipInteractorTest : SysuiTestCase() {
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+    val factory = kosmos.singleNotificationChipInteractorFactory
+
+    @Test
+    fun notificationChip_startsWithStartingModel() =
+        kosmos.runTest {
+            val icon = mock<StatusBarIconView>()
+            val startingNotif = activeNotificationModel(key = "notif1", statusBarChipIcon = icon)
+
+            val underTest = factory.create(startingNotif)
+
+            val latest by collectLastValue(underTest.notificationChip)
+
+            assertThat(latest!!.key).isEqualTo("notif1")
+            assertThat(latest!!.statusBarChipIconView).isEqualTo(icon)
+        }
+
+    @Test
+    fun notificationChip_updatesAfterSet() =
+        kosmos.runTest {
+            val originalIconView = mock<StatusBarIconView>()
+            val underTest =
+                factory.create(
+                    activeNotificationModel(key = "notif1", statusBarChipIcon = originalIconView)
+                )
+
+            val latest by collectLastValue(underTest.notificationChip)
+
+            val newIconView = mock<StatusBarIconView>()
+            underTest.setNotification(
+                activeNotificationModel(key = "notif1", statusBarChipIcon = newIconView)
+            )
+
+            assertThat(latest!!.key).isEqualTo("notif1")
+            assertThat(latest!!.statusBarChipIconView).isEqualTo(newIconView)
+        }
+
+    @Test
+    fun notificationChip_ignoresSetWithDifferentKey() =
+        kosmos.runTest {
+            val originalIconView = mock<StatusBarIconView>()
+            val underTest =
+                factory.create(
+                    activeNotificationModel(key = "notif1", statusBarChipIcon = originalIconView)
+                )
+
+            val latest by collectLastValue(underTest.notificationChip)
+
+            val newIconView = mock<StatusBarIconView>()
+            underTest.setNotification(
+                activeNotificationModel(key = "other_notif", statusBarChipIcon = newIconView)
+            )
+
+            assertThat(latest!!.key).isEqualTo("notif1")
+            assertThat(latest!!.statusBarChipIconView).isEqualTo(originalIconView)
+        }
+
+    @Test
+    fun notificationChip_missingStatusBarIconChipView_inConstructor_emitsNull() =
+        kosmos.runTest {
+            val underTest =
+                factory.create(activeNotificationModel(key = "notif1", statusBarChipIcon = null))
+
+            val latest by collectLastValue(underTest.notificationChip)
+
+            assertThat(latest).isNull()
+        }
+
+    @Test
+    fun notificationChip_missingStatusBarIconChipView_inSet_emitsNull() =
+        kosmos.runTest {
+            val startingNotif = activeNotificationModel(key = "notif1", statusBarChipIcon = mock())
+            val underTest = factory.create(startingNotif)
+            val latest by collectLastValue(underTest.notificationChip)
+            assertThat(latest).isNotNull()
+
+            underTest.setNotification(
+                activeNotificationModel(key = "notif1", statusBarChipIcon = null)
+            )
+
+            assertThat(latest).isNull()
+        }
+
+    @Test
+    fun notificationChip_appIsVisibleOnCreation_emitsNull() =
+        kosmos.runTest {
+            activityManagerRepository.fake.startingIsAppVisibleValue = true
+
+            val underTest =
+                factory.create(
+                    activeNotificationModel(key = "notif", uid = UID, statusBarChipIcon = mock())
+                )
+
+            val latest by collectLastValue(underTest.notificationChip)
+
+            assertThat(latest).isNull()
+        }
+
+    @Test
+    fun notificationChip_appNotVisibleOnCreation_emitsValue() =
+        kosmos.runTest {
+            activityManagerRepository.fake.startingIsAppVisibleValue = false
+
+            val underTest =
+                factory.create(
+                    activeNotificationModel(key = "notif", uid = UID, statusBarChipIcon = mock())
+                )
+
+            val latest by collectLastValue(underTest.notificationChip)
+
+            assertThat(latest).isNotNull()
+        }
+
+    @Test
+    fun notificationChip_hidesWhenAppIsVisible() =
+        kosmos.runTest {
+            val underTest =
+                factory.create(
+                    activeNotificationModel(key = "notif", uid = UID, statusBarChipIcon = mock())
+                )
+
+            val latest by collectLastValue(underTest.notificationChip)
+
+            activityManagerRepository.fake.setIsAppVisible(UID, false)
+            assertThat(latest).isNotNull()
+
+            activityManagerRepository.fake.setIsAppVisible(UID, true)
+            assertThat(latest).isNull()
+
+            activityManagerRepository.fake.setIsAppVisible(UID, false)
+            assertThat(latest).isNotNull()
+        }
+
+    // Note: This test is theoretically impossible because the notification key should contain the
+    // UID, so if the UID changes then the key would also change and a new interactor would be
+    // created. But, test it just in case.
+    @Test
+    fun notificationChip_updatedUid_rechecksAppVisibility_oldObserverUnregistered() =
+        kosmos.runTest {
+            activityManagerRepository.fake.startingIsAppVisibleValue = false
+
+            val hiddenUid = 100
+            val shownUid = 101
+
+            val underTest =
+                factory.create(
+                    activeNotificationModel(
+                        key = "notif",
+                        uid = hiddenUid,
+                        statusBarChipIcon = mock(),
+                    )
+                )
+            val latest by collectLastValue(underTest.notificationChip)
+            assertThat(latest).isNotNull()
+
+            // WHEN the notif gets a new UID that starts as visible
+            activityManagerRepository.fake.startingIsAppVisibleValue = true
+            underTest.setNotification(
+                activeNotificationModel(key = "notif", uid = shownUid, statusBarChipIcon = mock())
+            )
+
+            // THEN we re-fetch the app visibility state with the new UID, and since that UID is
+            // visible, we hide the chip
+            assertThat(latest).isNull()
+        }
+
+    companion object {
+        private const val UID = 885
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
index 19ed6a5..702e101 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
@@ -16,30 +16,277 @@
 
 package com.android.systemui.statusbar.chips.notification.domain.interactor
 
+import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.statusbar.StatusBarIconView
 import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
+import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
+import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
+import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
+import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlin.test.Test
 import kotlinx.coroutines.test.runTest
 import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
-@EnableFlags(StatusBarNotifChips.FLAG_NAME)
 class StatusBarNotificationChipsInteractorTest : SysuiTestCase() {
     private val kosmos = testKosmos().useUnconfinedTestDispatcher()
     private val testScope = kosmos.testScope
+    private val activeNotificationListRepository = kosmos.activeNotificationListRepository
 
-    private val underTest = kosmos.statusBarNotificationChipsInteractor
+    private val underTest by lazy {
+        kosmos.statusBarNotificationChipsInteractor.also { it.start() }
+    }
 
     @Test
+    @DisableFlags(StatusBarNotifChips.FLAG_NAME)
+    fun notificationChips_flagOff_noNotifs() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.notificationChips)
+
+            setNotifs(
+                listOf(
+                    activeNotificationModel(
+                        key = "notif",
+                        statusBarChipIcon = mock<StatusBarIconView>(),
+                        isPromoted = true,
+                    )
+                )
+            )
+
+            assertThat(latest).isEmpty()
+        }
+
+    @Test
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+    fun notificationChips_noNotifs_empty() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.notificationChips)
+
+            setNotifs(emptyList())
+
+            assertThat(latest).isEmpty()
+        }
+
+    @Test
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+    fun notificationChips_notifMissingStatusBarChipIconView_empty() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.notificationChips)
+
+            setNotifs(
+                listOf(
+                    activeNotificationModel(
+                        key = "notif",
+                        statusBarChipIcon = null,
+                        isPromoted = true,
+                    )
+                )
+            )
+
+            assertThat(latest).isEmpty()
+        }
+
+    @Test
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+    fun notificationChips_onePromotedNotif_statusBarIconViewMatches() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.notificationChips)
+
+            val icon = mock<StatusBarIconView>()
+            setNotifs(
+                listOf(
+                    activeNotificationModel(
+                        key = "notif",
+                        statusBarChipIcon = icon,
+                        isPromoted = true,
+                    )
+                )
+            )
+
+            assertThat(latest).hasSize(1)
+            assertThat(latest!![0].key).isEqualTo("notif")
+            assertThat(latest!![0].statusBarChipIconView).isEqualTo(icon)
+        }
+
+    @Test
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+    fun notificationChips_onlyForPromotedNotifs() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.notificationChips)
+
+            val firstIcon = mock<StatusBarIconView>()
+            val secondIcon = mock<StatusBarIconView>()
+            setNotifs(
+                listOf(
+                    activeNotificationModel(
+                        key = "notif1",
+                        statusBarChipIcon = firstIcon,
+                        isPromoted = true,
+                    ),
+                    activeNotificationModel(
+                        key = "notif2",
+                        statusBarChipIcon = secondIcon,
+                        isPromoted = true,
+                    ),
+                    activeNotificationModel(
+                        key = "notif3",
+                        statusBarChipIcon = mock<StatusBarIconView>(),
+                        isPromoted = false,
+                    ),
+                )
+            )
+
+            assertThat(latest).hasSize(2)
+            assertThat(latest!![0].key).isEqualTo("notif1")
+            assertThat(latest!![0].statusBarChipIconView).isEqualTo(firstIcon)
+            assertThat(latest!![1].key).isEqualTo("notif2")
+            assertThat(latest!![1].statusBarChipIconView).isEqualTo(secondIcon)
+        }
+
+    @Test
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+    fun notificationChips_notifUpdatesGoThrough() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.notificationChips)
+
+            val firstIcon = mock<StatusBarIconView>()
+            val secondIcon = mock<StatusBarIconView>()
+            val thirdIcon = mock<StatusBarIconView>()
+
+            setNotifs(
+                listOf(
+                    activeNotificationModel(
+                        key = "notif",
+                        statusBarChipIcon = firstIcon,
+                        isPromoted = true,
+                    )
+                )
+            )
+            assertThat(latest).hasSize(1)
+            assertThat(latest!![0].key).isEqualTo("notif")
+            assertThat(latest!![0].statusBarChipIconView).isEqualTo(firstIcon)
+
+            setNotifs(
+                listOf(
+                    activeNotificationModel(
+                        key = "notif",
+                        statusBarChipIcon = secondIcon,
+                        isPromoted = true,
+                    )
+                )
+            )
+            assertThat(latest).hasSize(1)
+            assertThat(latest!![0].key).isEqualTo("notif")
+            assertThat(latest!![0].statusBarChipIconView).isEqualTo(secondIcon)
+
+            setNotifs(
+                listOf(
+                    activeNotificationModel(
+                        key = "notif",
+                        statusBarChipIcon = thirdIcon,
+                        isPromoted = true,
+                    )
+                )
+            )
+            assertThat(latest).hasSize(1)
+            assertThat(latest!![0].key).isEqualTo("notif")
+            assertThat(latest!![0].statusBarChipIconView).isEqualTo(thirdIcon)
+        }
+
+    @Test
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+    fun notificationChips_promotedNotifDisappearsThenReappears() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.notificationChips)
+
+            setNotifs(
+                listOf(
+                    activeNotificationModel(
+                        key = "notif",
+                        statusBarChipIcon = mock(),
+                        isPromoted = true,
+                    )
+                )
+            )
+            assertThat(latest).hasSize(1)
+            assertThat(latest!![0].key).isEqualTo("notif")
+
+            setNotifs(
+                listOf(
+                    activeNotificationModel(
+                        key = "notif",
+                        statusBarChipIcon = mock(),
+                        isPromoted = false,
+                    )
+                )
+            )
+            assertThat(latest).isEmpty()
+
+            setNotifs(
+                listOf(
+                    activeNotificationModel(
+                        key = "notif",
+                        statusBarChipIcon = mock(),
+                        isPromoted = true,
+                    )
+                )
+            )
+            assertThat(latest).hasSize(1)
+            assertThat(latest!![0].key).isEqualTo("notif")
+        }
+
+    @Test
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+    fun notificationChips_notifChangesKey() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.notificationChips)
+
+            val firstIcon = mock<StatusBarIconView>()
+            val secondIcon = mock<StatusBarIconView>()
+            setNotifs(
+                listOf(
+                    activeNotificationModel(
+                        key = "notif|uid1",
+                        statusBarChipIcon = firstIcon,
+                        isPromoted = true,
+                    )
+                )
+            )
+            assertThat(latest).hasSize(1)
+            assertThat(latest!![0].key).isEqualTo("notif|uid1")
+            assertThat(latest!![0].statusBarChipIconView).isEqualTo(firstIcon)
+
+            // WHEN a notification changes UID, which is a key change
+            setNotifs(
+                listOf(
+                    activeNotificationModel(
+                        key = "notif|uid2",
+                        statusBarChipIcon = secondIcon,
+                        isPromoted = true,
+                    )
+                )
+            )
+
+            // THEN we correctly update
+            assertThat(latest).hasSize(1)
+            assertThat(latest!![0].key).isEqualTo("notif|uid2")
+            assertThat(latest!![0].statusBarChipIconView).isEqualTo(secondIcon)
+        }
+
+    @Test
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
     fun onPromotedNotificationChipTapped_emitsKeys() =
         testScope.runTest {
             val latest by collectValues(underTest.promotedNotificationChipTapEvent)
@@ -56,6 +303,7 @@
         }
 
     @Test
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
     fun onPromotedNotificationChipTapped_sameKeyTwice_emitsTwice() =
         testScope.runTest {
             val latest by collectValues(underTest.promotedNotificationChipTapEvent)
@@ -67,4 +315,11 @@
             assertThat(latest[0]).isEqualTo("fakeKey")
             assertThat(latest[1]).isEqualTo("fakeKey")
         }
+
+    private fun setNotifs(notifs: List<ActiveNotificationModel>) {
+        activeNotificationListRepository.activeNotifications.value =
+            ActiveNotificationsStore.Builder()
+                .apply { notifs.forEach { addIndividualNotif(it) } }
+                .build()
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
index 1b41329..16376c5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
@@ -22,7 +22,9 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
 import com.android.systemui.statusbar.StatusBarIconView
 import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor
 import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
@@ -34,26 +36,28 @@
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlin.test.Test
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
+import org.junit.Before
 import org.junit.runner.RunWith
 import org.mockito.kotlin.mock
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
-@OptIn(ExperimentalCoroutinesApi::class)
 @EnableFlags(StatusBarNotifChips.FLAG_NAME)
 class NotifChipsViewModelTest : SysuiTestCase() {
-    private val kosmos = testKosmos()
-    private val testScope = kosmos.testScope
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
     private val activeNotificationListRepository = kosmos.activeNotificationListRepository
 
-    private val underTest = kosmos.notifChipsViewModel
+    private val underTest by lazy { kosmos.notifChipsViewModel }
+
+    @Before
+    fun setUp() {
+        kosmos.statusBarNotificationChipsInteractor.start()
+    }
 
     @Test
     fun chips_noNotifs_empty() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.chips)
 
             setNotifs(emptyList())
@@ -63,7 +67,7 @@
 
     @Test
     fun chips_notifMissingStatusBarChipIconView_empty() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.chips)
 
             setNotifs(
@@ -81,7 +85,7 @@
 
     @Test
     fun chips_onePromotedNotif_statusBarIconViewMatches() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.chips)
 
             val icon = mock<StatusBarIconView>()
@@ -103,7 +107,7 @@
 
     @Test
     fun chips_onlyForPromotedNotifs() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.chips)
 
             val firstIcon = mock<StatusBarIconView>()
@@ -135,7 +139,7 @@
 
     @Test
     fun chips_clickingChipNotifiesInteractor() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.chips)
             val latestChipTap by
                 collectLastValue(
@@ -163,7 +167,6 @@
             ActiveNotificationsStore.Builder()
                 .apply { notifs.forEach { addIndividualNotif(it) } }
                 .build()
-        testScope.runCurrent()
     }
 
     companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
index 25d5ce5..eb0978e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
 import com.android.systemui.mediaprojection.data.model.MediaProjectionState
 import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
 import com.android.systemui.mediaprojection.taskswitcher.FakeActivityTaskManager.Companion.createTask
@@ -38,6 +39,7 @@
 import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.setUpPackageManagerForMediaProjection
 import com.android.systemui.statusbar.chips.notification.demo.ui.viewmodel.DemoNotifChipViewModelTest.Companion.addDemoNotifChip
 import com.android.systemui.statusbar.chips.notification.demo.ui.viewmodel.demoNotifChipViewModel
+import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor
 import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.chips.notification.ui.viewmodel.NotifChipsViewModelTest.Companion.assertIsNotifChip
 import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModel
@@ -67,6 +69,7 @@
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.kotlin.any
@@ -79,7 +82,7 @@
 @OptIn(ExperimentalCoroutinesApi::class)
 @EnableFlags(StatusBarNotifChips.FLAG_NAME)
 class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() {
-    private val kosmos = testKosmos()
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
     private val testScope = kosmos.testScope
     private val systemClock = kosmos.fakeSystemClock
     private val commandRegistry = kosmos.commandRegistry
@@ -103,12 +106,13 @@
                 .thenReturn(chipBackgroundView)
         }
 
-    private val underTest = kosmos.ongoingActivityChipsViewModel
+    private val underTest by lazy { kosmos.ongoingActivityChipsViewModel }
 
     @Before
     fun setUp() {
         setUpPackageManagerForMediaProjection(kosmos)
         kosmos.demoNotifChipViewModel.start()
+        kosmos.statusBarNotificationChipsInteractor.start()
         val icon =
             BitmapDrawable(
                 context.resources,
@@ -616,6 +620,7 @@
         }
 
     @Test
+    @Ignore("b/364653005") // We'll need to re-do the animation story when we implement RON chips
     fun primaryChip_screenRecordStoppedViaDialog_chipHiddenWithoutAnimation() =
         testScope.runTest {
             screenRecordState.value = ScreenRecordModel.Recording
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt
index cb92b77..a1772e3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt
@@ -14,11 +14,11 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
 import com.android.systemui.statusbar.notification.data.repository.NotificationLaunchAnimationRepository
 import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
+import com.android.systemui.statusbar.notification.headsup.HeadsUpUtil
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
-import com.android.systemui.statusbar.policy.HeadsUpManager
-import com.android.systemui.statusbar.policy.HeadsUpUtil
 import com.android.systemui.testKosmos
 import junit.framework.Assert.assertFalse
 import junit.framework.Assert.assertTrue
@@ -69,7 +69,7 @@
                 headsUpManager,
                 notification,
                 kosmos.interactionJankMonitor,
-                onFinishAnimationCallback
+                onFinishAnimationCallback,
             )
     }
 
@@ -95,7 +95,7 @@
                 notificationKey,
                 /* releaseImmediately= */ true,
                 /* animate= */ true,
-                /* reason= */ "onIntentStarted(willAnimate=false)"
+                /* reason= */ "onIntentStarted(willAnimate=false)",
             )
         verify(onFinishAnimationCallback).run()
     }
@@ -118,7 +118,7 @@
                 notificationKey,
                 /* releaseImmediately= */ true,
                 /* animate= */ true,
-                /* reason= */ "onLaunchAnimationCancelled()"
+                /* reason= */ "onLaunchAnimationCancelled()",
             )
         verify(onFinishAnimationCallback).run()
     }
@@ -141,7 +141,7 @@
                 notificationKey,
                 /* releaseImmediately= */ true,
                 /* animate= */ false,
-                /* reason= */ "onLaunchAnimationEnd()"
+                /* reason= */ "onLaunchAnimationEnd()",
             )
         verify(onFinishAnimationCallback).run()
     }
@@ -180,14 +180,14 @@
                 summary.key,
                 /* releaseImmediately= */ true,
                 /* animate= */ false,
-                /* reason= */ "onLaunchAnimationEnd()"
+                /* reason= */ "onLaunchAnimationEnd()",
             )
         verify(headsUpManager, never())
             .removeNotification(
                 notification.entry.key,
                 /* releaseImmediately= */ true,
                 /* animate= */ false,
-                /* reason= */ "onLaunchAnimationEnd()"
+                /* reason= */ "onLaunchAnimationEnd()",
             )
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
index c4b1b84..0dc01a6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
@@ -39,13 +39,13 @@
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.ShadeViewController.Companion.WAKEUP_ANIMATION_DELAY_MS
 import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_WAKEUP
 import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor
 import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.withArgCaptor
 import com.google.common.truth.Truth.assertThat
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
index 1f29255..544d201 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.notification.collection.coordinator;
 
 import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
+import static android.app.Notification.FLAG_PROMOTED_ONGOING;
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
 import static android.app.NotificationManager.IMPORTANCE_MIN;
@@ -24,12 +25,18 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.Person;
 import android.content.Intent;
 import android.graphics.Color;
 import android.os.UserHandle;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.testing.TestableLooper;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -38,11 +45,14 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -136,6 +146,60 @@
         assertFalse(mFgsSection.isInSection(mEntryBuilder.build()));
     }
 
+    @Test
+    @EnableFlags(PromotedNotificationUi.FLAG_NAME)
+    public void testIncludePromotedOngoingInSection_flagEnabled() {
+        // GIVEN the notification has FLAG_PROMOTED_ONGOING
+        mEntryBuilder.setFlag(mContext, FLAG_PROMOTED_ONGOING, true);
+
+        // THEN the entry is in the fgs section
+        assertTrue(mFgsSection.isInSection(mEntryBuilder.build()));
+    }
+
+    @Test
+    @DisableFlags(PromotedNotificationUi.FLAG_NAME)
+    public void testDiscludePromotedOngoingInSection_flagDisabled() {
+        // GIVEN the notification has FLAG_PROMOTED_ONGOING
+        mEntryBuilder.setFlag(mContext, FLAG_PROMOTED_ONGOING, true);
+
+        // THEN the entry is NOT in the fgs section
+        assertFalse(mFgsSection.isInSection(mEntryBuilder.build()));
+    }
+
+    @Test
+    @EnableFlags(PromotedNotificationUi.FLAG_NAME)
+    public void promoterSelectsPromotedOngoing_flagEnabled() {
+        ArgumentCaptor<NotifPromoter> captor = ArgumentCaptor.forClass(NotifPromoter.class);
+        verify(mNotifPipeline).addPromoter(captor.capture());
+        NotifPromoter promoter = captor.getValue();
+
+        // GIVEN the notification has FLAG_PROMOTED_ONGOING
+        mEntryBuilder.setFlag(mContext, FLAG_PROMOTED_ONGOING, true);
+
+        // THEN the entry is promoted to top level
+        assertTrue(promoter.shouldPromoteToTopLevel(mEntryBuilder.build()));
+    }
+
+    @Test
+    @EnableFlags(PromotedNotificationUi.FLAG_NAME)
+    public void promoterIgnoresNonPromotedOngoing_flagEnabled() {
+        ArgumentCaptor<NotifPromoter> captor = ArgumentCaptor.forClass(NotifPromoter.class);
+        verify(mNotifPipeline).addPromoter(captor.capture());
+        NotifPromoter promoter = captor.getValue();
+
+        // GIVEN the notification does not have FLAG_PROMOTED_ONGOING
+        mEntryBuilder.setFlag(mContext, FLAG_PROMOTED_ONGOING, false);
+
+        // THEN the entry is NOT promoted to top level
+        assertFalse(promoter.shouldPromoteToTopLevel(mEntryBuilder.build()));
+    }
+
+    @Test
+    @DisableFlags(PromotedNotificationUi.FLAG_NAME)
+    public void noPromoterAdded_flagDisabled() {
+        verify(mNotifPipeline, never()).addPromoter(any());
+    }
+
     private Notification.CallStyle makeCallStyle() {
         final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
                 new Intent("action"), PendingIntent.FLAG_IMMUTABLE);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index 2c488e3..1d7f257 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -38,12 +38,13 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
 import com.android.systemui.statusbar.notification.collection.mockNotifCollection
-import com.android.systemui.statusbar.notification.collection.notifCollection
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender.OnEndLifetimeExtensionCallback
 import com.android.systemui.statusbar.notification.collection.provider.LaunchFullScreenIntentProvider
 import com.android.systemui.statusbar.notification.collection.render.NodeController
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManagerImpl
+import com.android.systemui.statusbar.notification.headsup.OnHeadsUpChangedListener
 import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper.DecisionImpl
@@ -51,8 +52,6 @@
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider
 import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback
 import com.android.systemui.statusbar.phone.NotificationGroupTestHelper
-import com.android.systemui.statusbar.policy.BaseHeadsUpManager
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
 import com.android.systemui.testKosmos
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
@@ -84,7 +83,9 @@
 class HeadsUpCoordinatorTest : SysuiTestCase() {
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
-    private val statusBarNotificationChipsInteractor = kosmos.statusBarNotificationChipsInteractor
+    private val statusBarNotificationChipsInteractor by lazy {
+        kosmos.statusBarNotificationChipsInteractor
+    }
     private val notifCollection = kosmos.mockNotifCollection
 
     private lateinit var coordinator: HeadsUpCoordinator
@@ -101,7 +102,7 @@
 
     private val notifPipeline: NotifPipeline = mock()
     private val logger = HeadsUpCoordinatorLogger(logcatLogBuffer(), verbose = true)
-    private val headsUpManager: BaseHeadsUpManager = mock()
+    private val headsUpManager: HeadsUpManagerImpl = mock()
     private val headsUpViewBinder: HeadsUpViewBinder = mock()
     private val visualInterruptionDecisionProvider: VisualInterruptionDecisionProvider = mock()
     private val remoteInputManager: NotificationRemoteInputManager = mock()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/LockScreenMinimalismCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/LockScreenMinimalismCoordinatorTest.kt
index d772e3e..14148cd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/LockScreenMinimalismCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/LockScreenMinimalismCoordinatorTest.kt
@@ -21,7 +21,6 @@
 import android.app.NotificationManager.IMPORTANCE_DEFAULT
 import android.app.NotificationManager.IMPORTANCE_LOW
 import android.platform.test.annotations.EnableFlags
-import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -43,6 +42,7 @@
 import com.android.systemui.statusbar.notification.data.repository.FakeHeadsUpRowRepository
 import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
 import com.android.systemui.statusbar.notification.domain.interactor.lockScreenNotificationMinimalismSetting
+import com.android.systemui.statusbar.notification.headsup.PinnedStatus
 import com.android.systemui.statusbar.notification.shared.NotificationMinimalism
 import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
 import com.android.systemui.testKosmos
@@ -394,7 +394,7 @@
             assertThatTopUnseenKey().isEqualTo(solo1.key)
 
             // TEST: even being pinned doesn't take effect immediately
-            hunRepo1.isPinned.value = true
+            hunRepo1.pinnedStatus.value = PinnedStatus.PinnedBySystem
             testScheduler.advanceTimeBy(0.5.seconds)
             onBeforeTransformGroupsListener.onBeforeTransformGroups(listEntryList)
             assertThatTopUnseenKey().isEqualTo(solo1.key)
@@ -406,8 +406,8 @@
 
             // TEST: repeat; being heads up and pinned for 1 second triggers seen
             kosmos.headsUpNotificationRepository.orderedHeadsUpRows.value = listOf(hunRepo2)
-            hunRepo1.isPinned.value = false
-            hunRepo2.isPinned.value = true
+            hunRepo1.pinnedStatus.value = PinnedStatus.NotPinned
+            hunRepo2.pinnedStatus.value = PinnedStatus.PinnedBySystem
             testScheduler.advanceTimeBy(1.seconds)
             onBeforeTransformGroupsListener.onBeforeTransformGroups(listEntryList)
             assertThatTopUnseenKey().isEqualTo(null)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinatorTest.kt
index 3fd9c21..d38fb50 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinatorTest.kt
@@ -27,7 +27,6 @@
 import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.data.repository.keyguardRepository
-import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
 import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -48,9 +47,9 @@
 import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor
 import com.android.systemui.statusbar.notification.domain.interactor.lockScreenShowOnlyUnseenNotificationsSetting
 import com.android.systemui.statusbar.notification.domain.interactor.seenNotificationsInteractor
+import com.android.systemui.statusbar.notification.headsup.OnHeadsUpChangedListener
+import com.android.systemui.statusbar.notification.headsup.headsUpManager
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
-import com.android.systemui.statusbar.policy.headsUpManager
 import com.android.systemui.testKosmos
 import com.android.systemui.util.settings.FakeSettings
 import com.android.systemui.util.settings.fakeSettings
@@ -155,7 +154,7 @@
         runKeyguardCoordinatorTest {
             kosmos.setTransition(
                 sceneTransition = Idle(Scenes.Gone),
-                stateTransition = TransitionStep(KeyguardState.LOCKSCREEN, KeyguardState.GONE)
+                stateTransition = TransitionStep(KeyguardState.LOCKSCREEN, KeyguardState.GONE),
             )
 
             // WHEN: A notification is posted
@@ -170,7 +169,7 @@
             keyguardRepository.setKeyguardShowing(true)
             kosmos.setTransition(
                 sceneTransition = Idle(Scenes.Lockscreen),
-                stateTransition = TransitionStep(KeyguardState.GONE, KeyguardState.AOD)
+                stateTransition = TransitionStep(KeyguardState.GONE, KeyguardState.AOD),
             )
 
             // THEN: The notification is recognized as "seen" and is filtered out.
@@ -180,7 +179,7 @@
             keyguardRepository.setKeyguardShowing(false)
             kosmos.setTransition(
                 sceneTransition = Idle(Scenes.Gone),
-                stateTransition = TransitionStep(KeyguardState.AOD, KeyguardState.GONE)
+                stateTransition = TransitionStep(KeyguardState.AOD, KeyguardState.GONE),
             )
 
             // THEN: The notification is shown regardless
@@ -359,14 +358,14 @@
             keyguardRepository.setKeyguardShowing(false)
             kosmos.setTransition(
                 sceneTransition = Idle(Scenes.Gone),
-                stateTransition = TransitionStep(KeyguardState.LOCKSCREEN, KeyguardState.GONE)
+                stateTransition = TransitionStep(KeyguardState.LOCKSCREEN, KeyguardState.GONE),
             )
 
             // WHEN: Keyguard is shown again
             keyguardRepository.setKeyguardShowing(true)
             kosmos.setTransition(
                 sceneTransition = Idle(Scenes.Lockscreen),
-                stateTransition = TransitionStep(KeyguardState.GONE, KeyguardState.AOD)
+                stateTransition = TransitionStep(KeyguardState.GONE, KeyguardState.AOD),
             )
 
             // THEN: The notification is now recognized as "seen" and is filtered out.
@@ -412,7 +411,7 @@
         runKeyguardCoordinatorTest {
             kosmos.setTransition(
                 sceneTransition = Idle(Scenes.Lockscreen),
-                stateTransition = TransitionStep(KeyguardState.GONE, KeyguardState.LOCKSCREEN)
+                stateTransition = TransitionStep(KeyguardState.GONE, KeyguardState.LOCKSCREEN),
             )
             val firstEntry = NotificationEntryBuilder().setId(1).build()
             collectionListener.onEntryAdded(firstEntry)
@@ -435,14 +434,14 @@
             keyguardRepository.setKeyguardShowing(false)
             kosmos.setTransition(
                 sceneTransition = Idle(Scenes.Gone),
-                stateTransition = TransitionStep(KeyguardState.LOCKSCREEN, KeyguardState.GONE)
+                stateTransition = TransitionStep(KeyguardState.LOCKSCREEN, KeyguardState.GONE),
             )
 
             // WHEN: Keyguard is shown again
             keyguardRepository.setKeyguardShowing(true)
             kosmos.setTransition(
                 sceneTransition = Idle(Scenes.Lockscreen),
-                stateTransition = TransitionStep(KeyguardState.GONE, KeyguardState.LOCKSCREEN)
+                stateTransition = TransitionStep(KeyguardState.GONE, KeyguardState.LOCKSCREEN),
             )
 
             // THEN: The first notification is considered seen and is filtered out.
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
index 3ad41a5..ba85e32 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
@@ -67,7 +67,7 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
 import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.time.FakeSystemClock;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt
index d717fe4..dc0231f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.shade.shadeTestUtil
 import com.android.systemui.statusbar.notification.data.repository.FakeHeadsUpRowRepository
 import com.android.systemui.statusbar.notification.data.repository.notificationsKeyguardViewStateRepository
+import com.android.systemui.statusbar.notification.headsup.PinnedStatus
 import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
 import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
 import com.android.systemui.testKosmos
@@ -102,7 +103,7 @@
         }
 
     @Test
-    fun hasPinnedRows_rowGetsPinned_true() =
+    fun hasPinnedRows_rowGetsPinnedNormally_true() =
         testScope.runTest {
             val hasPinnedRows by collectLastValue(underTest.hasPinnedRows)
             // GIVEN no rows are pinned
@@ -115,8 +116,30 @@
             headsUpRepository.setNotifications(rows)
             runCurrent()
 
-            // WHEN a row gets pinned
-            rows[0].isPinned.value = true
+            // WHEN a row gets pinned normally
+            rows[0].pinnedStatus.value = PinnedStatus.PinnedBySystem
+            runCurrent()
+
+            // THEN hasPinnedRows updates to true
+            assertThat(hasPinnedRows).isTrue()
+        }
+
+    @Test
+    fun hasPinnedRows_rowGetsPinnedByUser_true() =
+        testScope.runTest {
+            val hasPinnedRows by collectLastValue(underTest.hasPinnedRows)
+            // GIVEN no rows are pinned
+            val rows =
+                arrayListOf(
+                    fakeHeadsUpRowRepository("key 0"),
+                    fakeHeadsUpRowRepository("key 1"),
+                    fakeHeadsUpRowRepository("key 2"),
+                )
+            headsUpRepository.setNotifications(rows)
+            runCurrent()
+
+            // WHEN a row gets pinned due to a chip tap
+            rows[0].pinnedStatus.value = PinnedStatus.PinnedByUser
             runCurrent()
 
             // THEN hasPinnedRows updates to true
@@ -138,7 +161,7 @@
             runCurrent()
 
             // THEN that row gets unpinned
-            rows[0].isPinned.value = false
+            rows[0].pinnedStatus.value = PinnedStatus.NotPinned
             runCurrent()
 
             // THEN hasPinnedRows updates to false
@@ -246,7 +269,7 @@
             runCurrent()
 
             // WHEN all rows gets pinned
-            rows[2].isPinned.value = true
+            rows[2].pinnedStatus.value = PinnedStatus.PinnedBySystem
             runCurrent()
 
             // THEN no rows are filtered
@@ -271,7 +294,7 @@
             assertThat(activeHeadsUpRows).containsExactly(rows[0], rows[1], rows[2])
 
             // WHEN all rows gets pinned
-            rows[2].isPinned.value = true
+            rows[2].pinnedStatus.value = PinnedStatus.PinnedBySystem
             runCurrent()
 
             // THEN no change
@@ -329,7 +352,7 @@
             runCurrent()
 
             // WHEN a row gets unpinned
-            rows[0].isPinned.value = false
+            rows[0].pinnedStatus.value = PinnedStatus.NotPinned
             runCurrent()
 
             // THEN the unpinned row is filtered
@@ -351,7 +374,7 @@
             runCurrent()
 
             // WHEN a row gets unpinned
-            rows[0].isPinned.value = false
+            rows[0].pinnedStatus.value = PinnedStatus.NotPinned
             runCurrent()
 
             // THEN all rows are still present
@@ -372,15 +395,15 @@
             headsUpRepository.setNotifications(rows)
             runCurrent()
 
-            rows[0].isPinned.value = true
+            rows[0].pinnedStatus.value = PinnedStatus.PinnedBySystem
             runCurrent()
             assertThat(pinnedHeadsUpRows).containsExactly(rows[0])
 
-            rows[0].isPinned.value = false
+            rows[0].pinnedStatus.value = PinnedStatus.NotPinned
             runCurrent()
             assertThat(pinnedHeadsUpRows).isEmpty()
 
-            rows[0].isPinned.value = true
+            rows[0].pinnedStatus.value = PinnedStatus.PinnedBySystem
             runCurrent()
             assertThat(pinnedHeadsUpRows).containsExactly(rows[0])
         }
@@ -485,7 +508,5 @@
         }
 
     private fun fakeHeadsUpRowRepository(key: String, isPinned: Boolean = false) =
-        FakeHeadsUpRowRepository(key = key, elementKey = Any()).apply {
-            this.isPinned.value = isPinned
-        }
+        FakeHeadsUpRowRepository(key = key, isPinned = isPinned)
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/AvalancheControllerTest.kt
similarity index 96%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/AvalancheControllerTest.kt
index c5eed73..22a9c64 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/AvalancheControllerTest.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.statusbar.policy
+package com.android.systemui.statusbar.notification.headsup
 
 import android.app.Notification
 import android.os.Handler
@@ -31,9 +31,11 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
 import com.android.systemui.statusbar.notification.collection.provider.visualStabilityProvider
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManagerTestUtil.createFullScreenIntentEntry
 import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
 import com.android.systemui.statusbar.phone.keyguardBypassController
-import com.android.systemui.statusbar.policy.HeadsUpManagerTestUtil.createFullScreenIntentEntry
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
+import com.android.systemui.statusbar.policy.configurationController
 import com.android.systemui.testKosmos
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.kotlin.JavaAdapter
@@ -76,7 +78,7 @@
     private val mGlobalSettings = FakeGlobalSettings()
     private val mSystemClock = FakeSystemClock()
     private val mExecutor = FakeExecutor(mSystemClock)
-    private lateinit var testableHeadsUpManager: BaseHeadsUpManager
+    private lateinit var testableHeadsUpManager: HeadsUpManagerImpl
 
     @Before
     fun setUp() {
@@ -114,7 +116,7 @@
             )
     }
 
-    private fun createHeadsUpEntry(id: Int): BaseHeadsUpManager.HeadsUpEntry {
+    private fun createHeadsUpEntry(id: Int): HeadsUpManagerImpl.HeadsUpEntry {
         return testableHeadsUpManager.createHeadsUpEntry(
             NotificationEntryBuilder()
                 .setSbn(HeadsUpManagerTestUtil.createSbn(id, Notification.Builder(mContext, "")))
@@ -122,7 +124,7 @@
         )
     }
 
-    private fun createFsiHeadsUpEntry(id: Int): BaseHeadsUpManager.HeadsUpEntry {
+    private fun createFsiHeadsUpEntry(id: Int): HeadsUpManagerImpl.HeadsUpEntry {
         return testableHeadsUpManager.createHeadsUpEntry(createFullScreenIntentEntry(id, mContext))
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.java
similarity index 86%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.java
index 0fbee6d..01f78cb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.policy;
+package com.android.systemui.statusbar.notification.headsup;
 
 import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
 
@@ -54,18 +54,17 @@
 import com.android.systemui.kosmos.KosmosJavaAdapter;
 import com.android.systemui.res.R;
 import com.android.systemui.shade.domain.interactor.ShadeInteractor;
-import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.settings.FakeGlobalSettings;
 import com.android.systemui.util.time.FakeSystemClock;
 
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -73,6 +72,7 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
+import kotlinx.coroutines.flow.StateFlowKt;
 import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
 import platform.test.runner.parameterized.Parameters;
 
@@ -81,8 +81,8 @@
 @SmallTest
 @TestableLooper.RunWithLooper
 @RunWith(ParameterizedAndroidJunit4.class)
-// TODO(b/378142453): Merge this with BaseHeadsUpManagerTest.
-public class BaseHeadsUpManagerTest extends SysuiTestCase {
+// TODO(b/378142453): Merge this with HeadsUpManagerPhoneTest.
+public class HeadsUpManagerImplTest extends SysuiTestCase {
     protected KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
 
     @Rule
@@ -119,7 +119,7 @@
         assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_A11Y_AUTO_DISMISS_TIME);
     }
 
-    private BaseHeadsUpManager createHeadsUpManager() {
+    private HeadsUpManagerImpl createHeadsUpManager() {
         return new TestableHeadsUpManager(
                 mContext,
                 mLogger,
@@ -169,7 +169,7 @@
         return FlagsParameterization.allCombinationsOf(NotificationThrottleHun.FLAG_NAME);
     }
 
-    public BaseHeadsUpManagerTest(FlagsParameterization flags) {
+    public HeadsUpManagerImplTest(FlagsParameterization flags) {
         mSetFlagsRule.setFlagsParameterization(flags);
     }
 
@@ -184,7 +184,7 @@
 
     @Test
     public void testHasNotifications_headsUpManagerMapNotEmpty_true() {
-        final BaseHeadsUpManager bhum = createHeadsUpManager();
+        final HeadsUpManagerImpl bhum = createHeadsUpManager();
         final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         bhum.showNotification(entry);
 
@@ -195,10 +195,10 @@
     @Test
     @EnableFlags(NotificationThrottleHun.FLAG_NAME)
     public void testHasNotifications_avalancheMapNotEmpty_true() {
-        final BaseHeadsUpManager bhum = createHeadsUpManager();
+        final HeadsUpManagerImpl bhum = createHeadsUpManager();
         final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
                 mContext);
-        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = bhum.createHeadsUpEntry(notifEntry);
+        final HeadsUpManagerImpl.HeadsUpEntry headsUpEntry = bhum.createHeadsUpEntry(notifEntry);
         mAvalancheController.addToNext(headsUpEntry, () -> {});
 
         assertThat(mAvalancheController.getWaitingEntryList()).isNotEmpty();
@@ -208,7 +208,7 @@
     @Test
     @EnableFlags(NotificationThrottleHun.FLAG_NAME)
     public void testHasNotifications_false() {
-        final BaseHeadsUpManager bhum = createHeadsUpManager();
+        final HeadsUpManagerImpl bhum = createHeadsUpManager();
         assertThat(bhum.mHeadsUpEntryMap).isEmpty();
         assertThat(mAvalancheController.getWaitingEntryList()).isEmpty();
         assertThat(bhum.hasNotifications()).isFalse();
@@ -217,10 +217,10 @@
     @Test
     @EnableFlags(NotificationThrottleHun.FLAG_NAME)
     public void testGetHeadsUpEntryList_includesAvalancheEntryList() {
-        final BaseHeadsUpManager bhum = createHeadsUpManager();
+        final HeadsUpManagerImpl bhum = createHeadsUpManager();
         final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
                 mContext);
-        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = bhum.createHeadsUpEntry(notifEntry);
+        final HeadsUpManagerImpl.HeadsUpEntry headsUpEntry = bhum.createHeadsUpEntry(notifEntry);
         mAvalancheController.addToNext(headsUpEntry, () -> {});
 
         assertThat(bhum.getHeadsUpEntryList()).contains(headsUpEntry);
@@ -229,10 +229,10 @@
     @Test
     @EnableFlags(NotificationThrottleHun.FLAG_NAME)
     public void testGetHeadsUpEntry_returnsAvalancheEntry() {
-        final BaseHeadsUpManager bhum = createHeadsUpManager();
+        final HeadsUpManagerImpl bhum = createHeadsUpManager();
         final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
                 mContext);
-        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = bhum.createHeadsUpEntry(notifEntry);
+        final HeadsUpManagerImpl.HeadsUpEntry headsUpEntry = bhum.createHeadsUpEntry(notifEntry);
         mAvalancheController.addToNext(headsUpEntry, () -> {});
 
         assertThat(bhum.getHeadsUpEntry(notifEntry.getKey())).isEqualTo(headsUpEntry);
@@ -240,7 +240,7 @@
 
     @Test
     public void testShowNotification_addsEntry() {
-        final BaseHeadsUpManager alm = createHeadsUpManager();
+        final HeadsUpManagerImpl alm = createHeadsUpManager();
         final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
@@ -252,7 +252,7 @@
 
     @Test
     public void testShowNotification_autoDismisses() {
-        final BaseHeadsUpManager alm = createHeadsUpManager();
+        final HeadsUpManagerImpl alm = createHeadsUpManager();
         final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
@@ -263,7 +263,7 @@
 
     @Test
     public void testRemoveNotification_removeDeferred() {
-        final BaseHeadsUpManager alm = createHeadsUpManager();
+        final HeadsUpManagerImpl alm = createHeadsUpManager();
         final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
@@ -276,7 +276,7 @@
 
     @Test
     public void testRemoveNotification_forceRemove() {
-        final BaseHeadsUpManager alm = createHeadsUpManager();
+        final HeadsUpManagerImpl alm = createHeadsUpManager();
         final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
@@ -289,7 +289,7 @@
 
     @Test
     public void testReleaseAllImmediately() {
-        final BaseHeadsUpManager alm = createHeadsUpManager();
+        final HeadsUpManagerImpl alm = createHeadsUpManager();
         for (int i = 0; i < TEST_NUM_NOTIFICATIONS; i++) {
             final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(i, mContext);
             entry.setRow(mRow);
@@ -303,7 +303,7 @@
 
     @Test
     public void testCanRemoveImmediately_notShownLongEnough() {
-        final BaseHeadsUpManager alm = createHeadsUpManager();
+        final HeadsUpManagerImpl alm = createHeadsUpManager();
         final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
@@ -314,11 +314,13 @@
 
     @Test
     public void testHunRemovedLogging() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
         final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
                 mContext);
-        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = mock(
-                BaseHeadsUpManager.HeadsUpEntry.class);
+        final HeadsUpManagerImpl.HeadsUpEntry headsUpEntry = mock(
+                HeadsUpManagerImpl.HeadsUpEntry.class);
+        when(headsUpEntry.getPinnedStatus())
+                .thenReturn(StateFlowKt.MutableStateFlow(PinnedStatus.NotPinned));
         headsUpEntry.mEntry = notifEntry;
 
         hum.onEntryRemoved(headsUpEntry, "test");
@@ -329,7 +331,7 @@
 
     @Test
     public void testShowNotification_autoDismissesIncludingTouchAcceptanceDelay() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
         final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(false);
 
@@ -342,7 +344,7 @@
 
     @Test
     public void testShowNotification_autoDismissesWithDefaultTimeout() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
         final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(false);
 
@@ -356,7 +358,7 @@
 
     @Test
     public void testShowNotification_stickyForSomeTime_autoDismissesWithStickyTimeout() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
         final NotificationEntry entry = createStickyForSomeTimeEntry(/* id = */ 0);
         useAccessibilityTimeout(false);
 
@@ -370,7 +372,7 @@
 
     @Test
     public void testShowNotification_sticky_neverAutoDismisses() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
         final NotificationEntry entry = createStickyEntry(/* id = */ 0);
         useAccessibilityTimeout(false);
 
@@ -383,7 +385,7 @@
 
     @Test
     public void testShowNotification_autoDismissesWithAccessibilityTimeout() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
         final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(true);
 
@@ -397,7 +399,7 @@
 
     @Test
     public void testShowNotification_stickyForSomeTime_autoDismissesWithAccessibilityTimeout() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
         final NotificationEntry entry = createStickyForSomeTimeEntry(/* id = */ 0);
         useAccessibilityTimeout(true);
 
@@ -411,7 +413,7 @@
 
     @Test
     public void testRemoveNotification_beforeMinimumDisplayTime() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
         final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(false);
 
@@ -430,7 +432,7 @@
 
     @Test
     public void testRemoveNotification_afterMinimumDisplayTime() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
         final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(false);
 
@@ -448,7 +450,7 @@
 
     @Test
     public void testRemoveNotification_releaseImmediately() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
         final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         hum.showNotification(entry);
@@ -462,7 +464,7 @@
 
     @Test
     public void testIsSticky_rowPinnedAndExpanded_true() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
         final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
                 mContext);
         when(mRow.isPinned()).thenReturn(true);
@@ -470,7 +472,7 @@
 
         hum.showNotification(notifEntry);
 
-        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
+        final HeadsUpManagerImpl.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
                 notifEntry.getKey());
         headsUpEntry.setExpanded(true);
 
@@ -479,13 +481,13 @@
 
     @Test
     public void testIsSticky_remoteInputActive_true() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
         final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
                 mContext);
 
         hum.showNotification(notifEntry);
 
-        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
+        final HeadsUpManagerImpl.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
                 notifEntry.getKey());
         headsUpEntry.mRemoteInputActive = true;
 
@@ -494,7 +496,7 @@
 
     @Test
     public void testIsSticky_hasFullScreenIntent_true() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
         final NotificationEntry notifEntry =
                 HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id = */ 0, mContext);
 
@@ -506,7 +508,7 @@
 
     @Test
     public void testIsSticky_stickyForSomeTime_false() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
         final NotificationEntry entry = createStickyForSomeTimeEntry(/* id = */ 0);
 
         hum.showNotification(entry);
@@ -517,13 +519,13 @@
 
     @Test
     public void testIsSticky_false() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
         final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
                 mContext);
 
         hum.showNotification(notifEntry);
 
-        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
+        final HeadsUpManagerImpl.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
                 notifEntry.getKey());
         headsUpEntry.setExpanded(false);
         headsUpEntry.mRemoteInputActive = false;
@@ -533,7 +535,7 @@
 
     @Test
     public void testCompareTo_withNullEntries() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
         final NotificationEntry alertEntry = new NotificationEntryBuilder().setTag("alert").build();
 
         hum.showNotification(alertEntry);
@@ -545,7 +547,7 @@
 
     @Test
     public void testCompareTo_withNonAlertEntries() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
 
         final NotificationEntry nonAlertEntry1 = new NotificationEntryBuilder().setTag(
                 "nae1").build();
@@ -561,9 +563,9 @@
 
     @Test
     public void testAlertEntryCompareTo_ongoingCallLessThanActiveRemoteInput() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
 
-        final BaseHeadsUpManager.HeadsUpEntry ongoingCall = hum.new HeadsUpEntry(
+        final HeadsUpManagerImpl.HeadsUpEntry ongoingCall = hum.new HeadsUpEntry(
                 new NotificationEntryBuilder()
                         .setSbn(HeadsUpManagerTestUtil.createSbn(/* id = */ 0,
                                 new Notification.Builder(mContext, "")
@@ -571,7 +573,7 @@
                                         .setOngoing(true)))
                         .build());
 
-        final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry(
+        final HeadsUpManagerImpl.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry(
                 HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext));
         activeRemoteInput.mRemoteInputActive = true;
 
@@ -581,11 +583,11 @@
 
     @Test
     public void testAlertEntryCompareTo_incomingCallLessThanActiveRemoteInput() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
 
         final Person person = new Person.Builder().setName("person").build();
         final PendingIntent intent = mock(PendingIntent.class);
-        final BaseHeadsUpManager.HeadsUpEntry incomingCall = hum.new HeadsUpEntry(
+        final HeadsUpManagerImpl.HeadsUpEntry incomingCall = hum.new HeadsUpEntry(
                 new NotificationEntryBuilder()
                         .setSbn(HeadsUpManagerTestUtil.createSbn(/* id = */ 0,
                                 new Notification.Builder(mContext, "")
@@ -593,7 +595,7 @@
                                                 .forIncomingCall(person, intent, intent))))
                         .build());
 
-        final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry(
+        final HeadsUpManagerImpl.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry(
                 HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext));
         activeRemoteInput.mRemoteInputActive = true;
 
@@ -604,10 +606,10 @@
     @Test
     @EnableFlags(NotificationThrottleHun.FLAG_NAME)
     public void testPinEntry_logsPeek_throttleEnabled() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
 
         // Needs full screen intent in order to be pinned
-        final BaseHeadsUpManager.HeadsUpEntry entryToPin = hum.new HeadsUpEntry(
+        final HeadsUpManagerImpl.HeadsUpEntry entryToPin = hum.new HeadsUpEntry(
                 HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id = */ 0, mContext));
 
         // Note: the standard way to show a notification would be calling showNotification rather
@@ -620,17 +622,17 @@
         assertEquals(2, mUiEventLoggerFake.numLogs());
         assertEquals(AvalancheController.ThrottleEvent.AVALANCHE_THROTTLING_HUN_SHOWN.getId(),
                 mUiEventLoggerFake.eventId(0));
-        assertEquals(BaseHeadsUpManager.NotificationPeekEvent.NOTIFICATION_PEEK.getId(),
+        assertEquals(HeadsUpManagerImpl.NotificationPeekEvent.NOTIFICATION_PEEK.getId(),
                 mUiEventLoggerFake.eventId(1));
     }
 
     @Test
     @DisableFlags(NotificationThrottleHun.FLAG_NAME)
     public void testPinEntry_logsPeek_throttleDisabled() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
 
         // Needs full screen intent in order to be pinned
-        final BaseHeadsUpManager.HeadsUpEntry entryToPin = hum.new HeadsUpEntry(
+        final HeadsUpManagerImpl.HeadsUpEntry entryToPin = hum.new HeadsUpEntry(
                 HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id = */ 0, mContext));
 
         // Note: the standard way to show a notification would be calling showNotification rather
@@ -641,13 +643,13 @@
         hum.onEntryAdded(entryToPin);
 
         assertEquals(1, mUiEventLoggerFake.numLogs());
-        assertEquals(BaseHeadsUpManager.NotificationPeekEvent.NOTIFICATION_PEEK.getId(),
+        assertEquals(HeadsUpManagerImpl.NotificationPeekEvent.NOTIFICATION_PEEK.getId(),
                 mUiEventLoggerFake.eventId(0));
     }
 
     @Test
     public void testSetUserActionMayIndirectlyRemove() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
+        final HeadsUpManagerImpl hum = createHeadsUpManager();
         final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
                 mContext);
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerPhoneTest.kt
similarity index 97%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerPhoneTest.kt
index 6175e05..35d8253 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerPhoneTest.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.statusbar.policy
+package com.android.systemui.statusbar.notification.headsup
 
 import android.os.Handler
 import android.platform.test.annotations.EnableFlags
@@ -35,6 +35,7 @@
 import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
 import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
 import com.android.systemui.testKosmos
 import com.android.systemui.util.concurrency.mockExecutorHandler
 import com.android.systemui.util.kotlin.JavaAdapter
@@ -58,7 +59,7 @@
 @SmallTest
 @RunWith(ParameterizedAndroidJunit4::class)
 @RunWithLooper
-class HeadsUpManagerPhoneTest(flags: FlagsParameterization) : BaseHeadsUpManagerTest(flags) {
+class HeadsUpManagerPhoneTest(flags: FlagsParameterization) : HeadsUpManagerImplTest(flags) {
 
     private val mHeadsUpManagerLogger = HeadsUpManagerLogger(logcatLogBuffer())
 
@@ -87,8 +88,8 @@
 
     @Mock private lateinit var mBgHandler: Handler
 
-    private fun createHeadsUpManagerPhone(): BaseHeadsUpManager {
-        return BaseHeadsUpManager(
+    private fun createHeadsUpManagerPhone(): HeadsUpManagerImpl {
+        return HeadsUpManagerImpl(
             mContext,
             mHeadsUpManagerLogger,
             statusBarStateController,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerTestUtil.java
similarity index 97%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerTestUtil.java
index 306d6efd..684ce59 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerTestUtil.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.policy;
+package com.android.systemui.statusbar.notification.headsup;
 import android.app.ActivityManager;
 import android.app.Notification;
 import android.app.PendingIntent;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/TestableHeadsUpManager.java
similarity index 90%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/TestableHeadsUpManager.java
index 59987f4..2b077ed 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/TestableHeadsUpManager.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.policy;
+package com.android.systemui.statusbar.notification.headsup;
 
 import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
 
@@ -33,12 +33,14 @@
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.settings.GlobalSettings;
 import com.android.systemui.util.time.SystemClock;
 
-class TestableHeadsUpManager extends BaseHeadsUpManager {
+class TestableHeadsUpManager extends HeadsUpManagerImpl {
 
     private HeadsUpEntry mLastCreatedEntry;
 
@@ -76,10 +78,10 @@
                 shadeInteractor,
                 avalancheController);
 
-        mTouchAcceptanceDelay = BaseHeadsUpManagerTest.TEST_TOUCH_ACCEPTANCE_TIME;
-        mMinimumDisplayTime = BaseHeadsUpManagerTest.TEST_MINIMUM_DISPLAY_TIME;
-        mAutoDismissTime = BaseHeadsUpManagerTest.TEST_AUTO_DISMISS_TIME;
-        mStickyForSomeTimeAutoDismissTime = BaseHeadsUpManagerTest.TEST_STICKY_AUTO_DISMISS_TIME;
+        mTouchAcceptanceDelay = HeadsUpManagerImplTest.TEST_TOUCH_ACCEPTANCE_TIME;
+        mMinimumDisplayTime = HeadsUpManagerImplTest.TEST_MINIMUM_DISPLAY_TIME;
+        mAutoDismissTime = HeadsUpManagerImplTest.TEST_AUTO_DISMISS_TIME;
+        mStickyForSomeTimeAutoDismissTime = HeadsUpManagerImplTest.TEST_STICKY_AUTO_DISMISS_TIME;
     }
 
     @NonNull
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
index 284efc7..d3bde84 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
@@ -70,13 +70,13 @@
 import com.android.systemui.statusbar.notification.NotifPipelineFlags
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.MAX_HUN_WHEN_AGE_MS
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.HUN_SUPPRESSED_OLD_WHEN
 import com.android.systemui.statusbar.policy.FakeDeviceProvisionedController
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.util.FakeEventLog
 import com.android.systemui.util.settings.FakeGlobalSettings
 import com.android.systemui.util.settings.FakeSettings
@@ -109,7 +109,7 @@
 
                     override fun isTagLoggable(tagName: String, level: LogLevel): Boolean = true
                 },
-            systrace = false
+            systrace = false,
         )
 
     private val leakCheck = LeakCheckedTest.SysuiLeakCheck()
@@ -162,10 +162,10 @@
     @Before
     fun setUp() {
         val userId = ActivityManager.getCurrentUser()
-        val user = UserInfo(userId, "Current user", /* flags = */ 0)
+        val user = UserInfo(userId, "Current user", /* flags= */ 0)
 
         deviceProvisionedController.currentUser = userId
-        userTracker.set(listOf(user), /* currentUserIndex = */ 0)
+        userTracker.set(listOf(user), /* currentUserIndex= */ 0)
         systemSettings = FakeSettings()
         whenever(bubbles.canShowBubbleNotification()).thenReturn(true)
         whenever(settingsInteractor.isCooldownEnabled).thenReturn(MutableStateFlow(true))
@@ -491,7 +491,7 @@
 
     private fun withPeekAndPulseEntry(
         extendEntry: EntryBuilder.() -> Unit,
-        block: (NotificationEntry) -> Unit
+        block: (NotificationEntry) -> Unit,
     ) {
         ensurePeekState()
         block(buildPeekEntry(extendEntry))
@@ -540,10 +540,10 @@
     @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_SILENT_FLAG)
     fun testShouldNotHeadsUp_silentNotification() {
         withPeekAndPulseEntry({
-                                  isGrouped = false
-                                  isGroupSummary = false
-                                  isSilent = true
-                              }) {
+            isGrouped = false
+            isGroupSummary = false
+            isSilent = true
+        }) {
             assertShouldNotHeadsUp(it)
             assertNoEventsLogged()
         }
@@ -553,10 +553,10 @@
     @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_SILENT_FLAG)
     fun testShouldHeadsUp_silentNotificationFalse() {
         withPeekAndPulseEntry({
-                                  isGrouped = false
-                                  isGroupSummary = false
-                                  isSilent = false
-                              }) {
+            isGrouped = false
+            isGroupSummary = false
+            isSilent = false
+        }) {
             assertShouldHeadsUp(it)
             assertNoEventsLogged()
         }
@@ -697,7 +697,7 @@
         forEachFsiState {
             assertShouldNotFsi(
                 buildFsiEntry { suppressedVisualEffects = SUPPRESSED_EFFECT_FULL_SCREEN_INTENT },
-                expectWouldInterruptWithoutDnd = true
+                expectWouldInterruptWithoutDnd = true,
             )
             assertNoEventsLogged()
         }
@@ -719,7 +719,7 @@
                     suppressedVisualEffects = SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
                     importance = IMPORTANCE_DEFAULT
                 },
-                expectWouldInterruptWithoutDnd = false
+                expectWouldInterruptWithoutDnd = false,
             )
             assertNoEventsLogged()
         }
@@ -754,7 +754,7 @@
         assertUiEventLogged(
             FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR,
             entry.sbn.uid,
-            entry.sbn.packageName
+            entry.sbn.packageName,
         )
         assertSystemEventLogged("231322873", entry.sbn.uid, "groupAlertBehavior")
     }
@@ -813,7 +813,7 @@
         assertUiEventLogged(
             FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA,
             entry.sbn.uid,
-            entry.sbn.packageName
+            entry.sbn.packageName,
         )
         assertSystemEventLogged("274759612", entry.sbn.uid, "bubbleMetadata")
     }
@@ -960,7 +960,7 @@
         var keyguardIsShowing: Boolean = false,
         var keyguardIsOccluded: Boolean = false,
         var deviceProvisioned: Boolean = true,
-        var currentUserSetup: Boolean = true
+        var currentUserSetup: Boolean = true,
     )
 
     protected fun setState(state: State): Unit =
@@ -1131,7 +1131,7 @@
 
     protected fun withLegacySuppressor(
         suppressor: NotificationInterruptSuppressor,
-        block: () -> Unit
+        block: () -> Unit,
     ) {
         provider.addLegacySuppressor(suppressor)
         block()
@@ -1166,7 +1166,7 @@
 
     protected fun assertShouldNotFsi(
         entry: NotificationEntry,
-        expectWouldInterruptWithoutDnd: Boolean? = null
+        expectWouldInterruptWithoutDnd: Boolean? = null,
     ) =
         provider.makeUnloggedFullScreenIntentDecision(entry).let {
             provider.logFullScreenIntentDecision(it)
@@ -1175,7 +1175,7 @@
                 assertEquals(
                     "unexpected wouldInterruptWithoutDnd for FSI: ${it.logReason}",
                     expectWouldInterruptWithoutDnd,
-                    it.wouldInterruptWithoutDnd
+                    it.wouldInterruptWithoutDnd,
                 )
             }
         }
@@ -1227,9 +1227,9 @@
                             context,
                             /* requestCode = */ 0,
                             Intent().setPackage(context.packageName),
-                            FLAG_MUTABLE
+                            FLAG_MUTABLE,
                         ),
-                        Icon.createWithResource(context.resources, R.drawable.android)
+                        Icon.createWithResource(context.resources, R.drawable.android),
                     )
                 }
 
@@ -1272,7 +1272,7 @@
                     }
 
                     if (hasFsi) {
-                        nb.setFullScreenIntent(mock(), /* highPriority = */ true)
+                        nb.setFullScreenIntent(mock(), /* highPriority= */ true)
                     }
                 }
                 .build()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
index 7fd9c9f..ff8ef18 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
@@ -27,9 +27,9 @@
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.shared.notifications.domain.interactor.NotificationSettingsInteractor
 import com.android.systemui.statusbar.notification.NotifPipelineFlags
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.policy.BatteryController
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.EventLog
 import com.android.systemui.util.settings.GlobalSettings
@@ -63,7 +63,7 @@
         bubbles: Optional<Bubbles>,
         context: Context,
         notificationManager: NotificationManager,
-        settingsInteractor: NotificationSettingsInteractor
+        settingsInteractor: NotificationSettingsInteractor,
     ): VisualInterruptionDecisionProvider {
         return if (VisualInterruptionRefactor.isEnabled) {
             VisualInterruptionDecisionProviderImpl(
@@ -88,7 +88,7 @@
                 bubbles,
                 context,
                 notificationManager,
-                settingsInteractor
+                settingsInteractor,
             )
         } else {
             NotificationInterruptStateProviderWrapper(
@@ -109,7 +109,7 @@
                     systemClock,
                     globalSettings,
                     eventLog,
-                    bubbles
+                    bubbles,
                 )
             )
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorTest.kt
new file mode 100644
index 0000000..6736ccf
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorTest.kt
@@ -0,0 +1,210 @@
+/*
+ * 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.statusbar.notification.promoted
+
+import android.app.Notification
+import android.app.Notification.BigPictureStyle
+import android.app.Notification.BigTextStyle
+import android.app.Notification.CallStyle
+import android.app.Notification.MessagingStyle
+import android.app.Notification.ProgressStyle
+import android.app.Notification.ProgressStyle.Segment
+import android.app.PendingIntent
+import android.app.Person
+import android.content.Intent
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Style
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class PromotedNotificationContentExtractorTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+
+    private val provider =
+        FakePromotedNotificationsProvider().also { kosmos.promotedNotificationsProvider = it }
+
+    private val underTest = kosmos.promotedNotificationContentExtractor
+
+    @Test
+    @DisableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME)
+    fun shouldNotExtract_bothFlagsDisabled() {
+        val notif = createEntry().also { provider.promotedEntries.add(it) }
+        val content = extractContent(notif)
+        assertThat(content).isNull()
+    }
+
+    @Test
+    @EnableFlags(PromotedNotificationUi.FLAG_NAME)
+    @DisableFlags(StatusBarNotifChips.FLAG_NAME)
+    fun shouldExtract_promotedNotificationUiFlagEnabled() {
+        val entry = createEntry().also { provider.promotedEntries.add(it) }
+        val content = extractContent(entry)
+        assertThat(content).isNotNull()
+    }
+
+    @Test
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+    @DisableFlags(PromotedNotificationUi.FLAG_NAME)
+    fun shouldExtract_statusBarNotifChipsFlagEnabled() {
+        val entry = createEntry().also { provider.promotedEntries.add(it) }
+        val content = extractContent(entry)
+        assertThat(content).isNotNull()
+    }
+
+    @Test
+    @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME)
+    fun shouldExtract_bothFlagsEnabled() {
+        val entry = createEntry().also { provider.promotedEntries.add(it) }
+        val content = extractContent(entry)
+        assertThat(content).isNotNull()
+    }
+
+    @Test
+    @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME)
+    fun shouldNotExtract_providerDidNotPromote() {
+        val entry = createEntry().also { provider.promotedEntries.remove(it) }
+        val content = extractContent(entry)
+        assertThat(content).isNull()
+    }
+
+    @Test
+    @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME)
+    fun extractContent_commonFields() {
+        val entry =
+            createEntry {
+                    setSubText(TEST_SUB_TEXT)
+                    setContentTitle(TEST_CONTENT_TITLE)
+                    setContentText(TEST_CONTENT_TEXT)
+                }
+                .also { provider.promotedEntries.add(it) }
+
+        val content = extractContent(entry)
+
+        assertThat(content).isNotNull()
+        assertThat(content?.subText).isEqualTo(TEST_SUB_TEXT)
+        assertThat(content?.title).isEqualTo(TEST_CONTENT_TITLE)
+        assertThat(content?.text).isEqualTo(TEST_CONTENT_TEXT)
+    }
+
+    @Test
+    @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME)
+    fun extractContent_fromBigPictureStyle() {
+        val entry =
+            createEntry { setStyle(BigPictureStyle()) }.also { provider.promotedEntries.add(it) }
+
+        val content = extractContent(entry)
+
+        assertThat(content).isNotNull()
+        assertThat(content?.style).isEqualTo(Style.BigPicture)
+    }
+
+    @Test
+    @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME)
+    fun extractContent_fromBigTextStyle() {
+        val entry =
+            createEntry { setStyle(BigTextStyle()) }.also { provider.promotedEntries.add(it) }
+
+        val content = extractContent(entry)
+
+        assertThat(content).isNotNull()
+        assertThat(content?.style).isEqualTo(Style.BigText)
+    }
+
+    @Test
+    @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME)
+    fun extractContent_fromCallStyle() {
+        val hangUpIntent =
+            PendingIntent.getBroadcast(context, 0, Intent("hangup"), PendingIntent.FLAG_IMMUTABLE)
+
+        val entry =
+            createEntry { setStyle(CallStyle.forOngoingCall(TEST_PERSON, hangUpIntent)) }
+                .also { provider.promotedEntries.add(it) }
+
+        val content = extractContent(entry)
+
+        assertThat(content).isNotNull()
+        assertThat(content?.style).isEqualTo(Style.Call)
+    }
+
+    @Test
+    @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME)
+    fun extractContent_fromProgressStyle() {
+        val entry =
+            createEntry {
+                    setStyle(ProgressStyle().addProgressSegment(Segment(100)).setProgress(75))
+                }
+                .also { provider.promotedEntries.add(it) }
+
+        val content = extractContent(entry)
+
+        assertThat(content).isNotNull()
+        assertThat(content?.style).isEqualTo(Style.Progress)
+        assertThat(content?.progress).isNotNull()
+        assertThat(content?.progress?.progress).isEqualTo(75)
+        assertThat(content?.progress?.progressMax).isEqualTo(100)
+    }
+
+    @Test
+    @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME)
+    fun extractContent_fromIneligibleStyle() {
+        val entry =
+            createEntry {
+                    setStyle(
+                        MessagingStyle(TEST_PERSON).addMessage("message text", 0L, TEST_PERSON)
+                    )
+                }
+                .also { provider.promotedEntries.add(it) }
+
+        val content = extractContent(entry)
+
+        assertThat(content).isNotNull()
+        assertThat(content?.style).isEqualTo(Style.Ineligible)
+    }
+
+    private fun extractContent(entry: NotificationEntry): PromotedNotificationContentModel? {
+        val recoveredBuilder = Notification.Builder(context, entry.sbn.notification)
+        return underTest.extractContent(entry, recoveredBuilder)
+    }
+
+    private fun createEntry(builderBlock: Notification.Builder.() -> Unit = {}): NotificationEntry {
+        val notif = Notification.Builder(context, "a").also(builderBlock).build()
+        return NotificationEntryBuilder().setNotification(notif).build()
+    }
+
+    companion object {
+        private const val TEST_SUB_TEXT = "sub text"
+        private const val TEST_CONTENT_TITLE = "content title"
+        private const val TEST_CONTENT_TEXT = "content text"
+
+        private const val TEST_PERSON_NAME = "person name"
+        private const val TEST_PERSON_KEY = "person key"
+        private val TEST_PERSON =
+            Person.Builder().setKey(TEST_PERSON_KEY).setName(TEST_PERSON_NAME).build()
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
index 657e9df..ca0f9ef 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
@@ -42,6 +42,7 @@
 import com.android.systemui.statusbar.notification.collection.render.FakeNodeController
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController.BUBBLES_SETTING_URI
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer
@@ -49,7 +50,6 @@
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
 import com.android.systemui.statusbar.notification.stack.ui.view.NotificationRowStatsLogger
 import com.android.systemui.statusbar.phone.KeyguardBypassController
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.SmartReplyConstants
 import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent
 import com.android.systemui.util.mockito.any
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
index 1c5f37c..979a1d0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
@@ -40,8 +40,9 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.shade.ShadeController;
+import com.android.systemui.statusbar.notification.headsup.PinnedStatus;
 import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -91,7 +92,7 @@
         ExpandableNotificationRowDragController controller = createSpyController();
         mRow.setDragController(controller);
         mRow.setHeadsUp(true);
-        mRow.setPinned(true);
+        mRow.setPinnedStatus(PinnedStatus.PinnedBySystem);
 
         mRow.doLongClickCallback(0, 0);
         mRow.doDragCallback(0, 0);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index b278f1a..6eb2764 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -30,6 +30,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -42,6 +43,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.util.TypedValue;
@@ -56,8 +58,12 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.media.controls.util.MediaFeatureFlag;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
 import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor;
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi;
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel;
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.BindParams;
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationCallback;
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
@@ -99,6 +105,7 @@
     @Mock private NotifLayoutInflaterFactory.Provider mNotifLayoutInflaterFactoryProvider;
     @Mock private HeadsUpStyleProvider mHeadsUpStyleProvider;
     @Mock private NotifLayoutInflaterFactory mNotifLayoutInflaterFactory;
+    @Mock private PromotedNotificationContentExtractor mPromotedNotificationContentExtractor;
 
     private final SmartReplyStateInflater mSmartReplyStateInflater =
             new SmartReplyStateInflater() {
@@ -142,6 +149,7 @@
                 mSmartReplyStateInflater,
                 mNotifLayoutInflaterFactoryProvider,
                 mHeadsUpStyleProvider,
+                mPromotedNotificationContentExtractor,
                 mock(NotificationRowContentBinderLogger.class));
     }
 
@@ -382,6 +390,75 @@
         verify(mRow, times(0)).onNotificationUpdated();
     }
 
+    @Test
+    @DisableFlags({PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME})
+    public void testExtractsPromotedContent_notWhenBothFlagsDisabled() throws Exception {
+        final PromotedNotificationContentModel content =
+                new PromotedNotificationContentModel.Builder("key").build();
+        when(mPromotedNotificationContentExtractor.extractContent(any(), any()))
+                .thenReturn(content);
+
+        inflateAndWait(mNotificationInflater, FLAG_CONTENT_VIEW_ALL, mRow);
+
+        verify(mPromotedNotificationContentExtractor, never()).extractContent(any(), any());
+    }
+
+    @Test
+    @EnableFlags(PromotedNotificationUi.FLAG_NAME)
+    @DisableFlags(StatusBarNotifChips.FLAG_NAME)
+    public void testExtractsPromotedContent_whenPromotedNotificationUiFlagEnabled()
+            throws Exception {
+        final PromotedNotificationContentModel content =
+                new PromotedNotificationContentModel.Builder("key").build();
+        when(mPromotedNotificationContentExtractor.extractContent(any(), any()))
+                .thenReturn(content);
+
+        inflateAndWait(mNotificationInflater, FLAG_CONTENT_VIEW_ALL, mRow);
+
+        verify(mPromotedNotificationContentExtractor, times(1)).extractContent(any(), any());
+        assertEquals(content, mRow.getEntry().getPromotedNotificationContentModel());
+    }
+
+    @Test
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+    @DisableFlags(PromotedNotificationUi.FLAG_NAME)
+    public void testExtractsPromotedContent_whenStatusBarNotifChipsFlagEnabled() throws Exception {
+        final PromotedNotificationContentModel content =
+                new PromotedNotificationContentModel.Builder("key").build();
+        when(mPromotedNotificationContentExtractor.extractContent(any(), any()))
+                .thenReturn(content);
+
+        inflateAndWait(mNotificationInflater, FLAG_CONTENT_VIEW_ALL, mRow);
+
+        verify(mPromotedNotificationContentExtractor, times(1)).extractContent(any(), any());
+        assertEquals(content, mRow.getEntry().getPromotedNotificationContentModel());
+    }
+
+    @Test
+    @EnableFlags({PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME})
+    public void testExtractsPromotedContent_whenBothFlagsEnabled() throws Exception {
+        final PromotedNotificationContentModel content =
+                new PromotedNotificationContentModel.Builder("key").build();
+        when(mPromotedNotificationContentExtractor.extractContent(any(), any()))
+                .thenReturn(content);
+
+        inflateAndWait(mNotificationInflater, FLAG_CONTENT_VIEW_ALL, mRow);
+
+        verify(mPromotedNotificationContentExtractor, times(1)).extractContent(any(), any());
+        assertEquals(content, mRow.getEntry().getPromotedNotificationContentModel());
+    }
+
+    @Test
+    @EnableFlags({PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME})
+    public void testExtractsPromotedContent_null() throws Exception {
+        when(mPromotedNotificationContentExtractor.extractContent(any(), any())).thenReturn(null);
+
+        inflateAndWait(mNotificationInflater, FLAG_CONTENT_VIEW_ALL, mRow);
+
+        verify(mPromotedNotificationContentExtractor, times(1)).extractContent(any(), any());
+        assertNull(mRow.getEntry().getPromotedNotificationContentModel());
+    }
+
     private static void inflateAndWait(NotificationContentInflater inflater,
             @InflationFlag int contentToInflate,
             ExpandableNotificationRow row)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
index b16d3ea..6a0a5bb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
@@ -71,10 +71,10 @@
 import com.android.systemui.statusbar.notification.NotificationActivityStarter
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
 import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.testKosmos
 import com.android.systemui.util.kotlin.JavaAdapter
 import com.android.systemui.wmshell.BubblesManager
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt
index 48608eb..1851799 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt
@@ -21,6 +21,7 @@
 import android.os.AsyncTask
 import android.os.Build
 import android.os.CancellationSignal
+import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import android.testing.TestableLooper.RunWithLooper
 import android.util.TypedValue
@@ -33,8 +34,12 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.notification.ConversationNotificationProcessor
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.BindParams
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED
@@ -62,6 +67,7 @@
 import org.mockito.kotlin.any
 import org.mockito.kotlin.eq
 import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
 import org.mockito.kotlin.spy
 import org.mockito.kotlin.times
 import org.mockito.kotlin.verify
@@ -82,7 +88,7 @@
         object : NotifLayoutInflaterFactory.Provider {
             override fun provide(
                 row: ExpandableNotificationRow,
-                layoutType: Int
+                layoutType: Int,
             ): NotifLayoutInflaterFactory = mock()
         }
     private val smartReplyStateInflater: SmartReplyStateInflater =
@@ -95,7 +101,7 @@
                 notifPackageContext: Context,
                 entry: NotificationEntry,
                 existingSmartReplyState: InflatedSmartReplyState?,
-                newSmartReplyState: InflatedSmartReplyState
+                newSmartReplyState: InflatedSmartReplyState,
             ): InflatedSmartReplyViewHolder {
                 return inflatedSmartReplies
             }
@@ -104,6 +110,7 @@
                 return inflatedSmartReplyState
             }
         }
+    private val promotedNotificationContentExtractor: PromotedNotificationContentExtractor = mock()
 
     @Before
     fun setUp() {
@@ -125,7 +132,8 @@
                 smartReplyStateInflater,
                 layoutInflaterFactoryProvider,
                 mock<HeadsUpStyleProvider>(),
-                mock()
+                promotedNotificationContentExtractor,
+                mock(),
             )
     }
 
@@ -142,7 +150,8 @@
             FLAG_CONTENT_VIEW_ALL,
             builder,
             mContext,
-            smartReplyStateInflater
+            smartReplyStateInflater,
+            mock(),
         )
         verify(builder).createHeadsUpContentView(true)
     }
@@ -160,7 +169,8 @@
             FLAG_CONTENT_VIEW_ALL,
             builder,
             mContext,
-            smartReplyStateInflater
+            smartReplyStateInflater,
+            mock(),
         )
         verify(builder).createContentView(true)
     }
@@ -187,7 +197,7 @@
             true /* expectingException */,
             notificationInflater,
             FLAG_CONTENT_VIEW_ALL,
-            row
+            row,
         )
         Assert.assertTrue(row.privateLayout.childCount == 0)
         verify(row, times(0)).onNotificationUpdated()
@@ -210,7 +220,7 @@
             FLAG_CONTENT_VIEW_ALL,
             BindParams(),
             false /* forceInflate */,
-            null /* callback */
+            null, /* callback */
         )
         Assert.assertNull(row.entry.runningTask)
     }
@@ -223,7 +233,8 @@
             NotificationRowContentBinderImpl.InflationProgress(
                 packageContext = mContext,
                 remoteViews = NewRemoteViews(),
-                contentModel = NotificationContentModel(headsUpStatusBarModel)
+                contentModel = NotificationContentModel(headsUpStatusBarModel),
+                extractedPromotedNotificationContentModel = null,
             )
         val countDownLatch = CountDownLatch(1)
         NotificationRowContentBinderImpl.applyRemoteView(
@@ -261,7 +272,7 @@
                         get() =
                             AsyncFailRemoteView(
                                 mContext.packageName,
-                                com.android.systemui.tests.R.layout.custom_view_dark
+                                com.android.systemui.tests.R.layout.custom_view_dark,
                             )
                 },
             logger = mock(),
@@ -280,7 +291,7 @@
         val decoratedMediaView = builder.createContentView()
         Assert.assertFalse(
             "The decorated media style doesn't allow a view to be reapplied!",
-            NotificationRowContentBinderImpl.canReapplyRemoteView(mediaView, decoratedMediaView)
+            NotificationRowContentBinderImpl.canReapplyRemoteView(mediaView, decoratedMediaView),
         )
     }
 
@@ -304,7 +315,7 @@
         Assert.assertEquals(
             "Binder inflated a new view even though the old one was cached and usable.",
             view,
-            row.privateLayout.contractedChild
+            row.privateLayout.contractedChild,
         )
     }
 
@@ -327,7 +338,7 @@
         Assert.assertNotEquals(
             "Binder (somehow) used the same view when inflating.",
             view,
-            row.privateLayout.contractedChild
+            row.privateLayout.contractedChild,
         )
     }
 
@@ -396,7 +407,7 @@
     private fun getValidationError(
         measuredHeightDp: Float,
         targetSdk: Int,
-        contentView: RemoteViews?
+        contentView: RemoteViews?,
     ): String? {
         val view: View = mock()
         whenever(view.measuredHeight)
@@ -404,7 +415,7 @@
                 TypedValue.applyDimension(
                         COMPLEX_UNIT_SP,
                         measuredHeightDp,
-                        mContext.resources.displayMetrics
+                        mContext.resources.displayMetrics,
                     )
                     .toInt()
             )
@@ -419,7 +430,7 @@
         row.entry.sbn.notification.contentView =
             RemoteViews(
                 mContext.packageName,
-                com.android.systemui.tests.R.layout.invalid_notification_height
+                com.android.systemui.tests.R.layout.invalid_notification_height,
             )
         inflateAndWait(true, notificationInflater, FLAG_CONTENT_VIEW_ALL, row)
         Assert.assertEquals(0, row.privateLayout.childCount.toLong())
@@ -451,7 +462,7 @@
             false,
             notificationInflater,
             FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE,
-            messagingRow
+            messagingRow,
         )
         Assert.assertNotNull(messagingRow.publicLayout.mSingleLineView)
         // assert this is the conversation layout
@@ -460,6 +471,59 @@
         )
     }
 
+    @Test
+    @DisableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME)
+    fun testExtractsPromotedContent_notWhenBothFlagsDisabled() {
+        val content = PromotedNotificationContentModel.Builder("key").build()
+        whenever(promotedNotificationContentExtractor.extractContent(any(), any()))
+            .thenReturn(content)
+
+        inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_ALL, row)
+
+        verify(promotedNotificationContentExtractor, never()).extractContent(any(), any())
+    }
+
+    @Test
+    @EnableFlags(PromotedNotificationUi.FLAG_NAME)
+    @DisableFlags(StatusBarNotifChips.FLAG_NAME)
+    fun testExtractsPromotedContent_whenPromotedNotificationUiFlagEnabled() {
+        val content = PromotedNotificationContentModel.Builder("key").build()
+        whenever(promotedNotificationContentExtractor.extractContent(any(), any()))
+            .thenReturn(content)
+
+        inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_ALL, row)
+
+        verify(promotedNotificationContentExtractor, times(1)).extractContent(any(), any())
+        Assert.assertEquals(content, row.entry.promotedNotificationContentModel)
+    }
+
+    @Test
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+    @DisableFlags(PromotedNotificationUi.FLAG_NAME)
+    fun testExtractsPromotedContent_whenStatusBarNotifChipsFlagEnabled() {
+        val content = PromotedNotificationContentModel.Builder("key").build()
+        whenever(promotedNotificationContentExtractor.extractContent(any(), any()))
+            .thenReturn(content)
+
+        inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_ALL, row)
+
+        verify(promotedNotificationContentExtractor, times(1)).extractContent(any(), any())
+        Assert.assertEquals(content, row.entry.promotedNotificationContentModel)
+    }
+
+    @Test
+    @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME)
+    fun testExtractsPromotedContent_whenBothFlagsEnabled() {
+        val content = PromotedNotificationContentModel.Builder("key").build()
+        whenever(promotedNotificationContentExtractor.extractContent(any(), any()))
+            .thenReturn(content)
+
+        inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_ALL, row)
+
+        verify(promotedNotificationContentExtractor, times(1)).extractContent(any(), any())
+        Assert.assertEquals(content, row.entry.promotedNotificationContentModel)
+    }
+
     private class ExceptionHolder {
         var exception: Exception? = null
     }
@@ -476,7 +540,7 @@
             parent: ViewGroup,
             executor: Executor,
             listener: OnViewAppliedListener,
-            handler: InteractionHandler?
+            handler: InteractionHandler?,
         ): CancellationSignal {
             executor.execute { listener.onError(RuntimeException("Failed to inflate async")) }
             return CancellationSignal()
@@ -486,7 +550,7 @@
             context: Context,
             parent: ViewGroup,
             executor: Executor,
-            listener: OnViewAppliedListener
+            listener: OnViewAppliedListener,
         ): CancellationSignal {
             return applyAsync(context, parent, executor, listener, null)
         }
@@ -496,7 +560,7 @@
         private fun inflateAndWait(
             inflater: NotificationRowContentBinderImpl,
             @InflationFlag contentToInflate: Int,
-            row: ExpandableNotificationRow
+            row: ExpandableNotificationRow,
         ) {
             inflateAndWait(false /* expectingException */, inflater, contentToInflate, row)
         }
@@ -535,7 +599,7 @@
                 contentToInflate,
                 BindParams(),
                 false /* forceInflate */,
-                callback /* callback */
+                callback, /* callback */
             )
             Assert.assertTrue(countDownLatch.await(500, TimeUnit.MILLISECONDS))
             exceptionHolder.exception?.let { throw it }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 2340d02..080ac3f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -82,13 +82,14 @@
 import com.android.systemui.statusbar.notification.icon.IconBuilder;
 import com.android.systemui.statusbar.notification.icon.IconManager;
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.ExpandableNotificationRowLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.OnExpandClickListener;
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
 import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor;
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
 import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder;
 import com.android.systemui.statusbar.policy.SmartReplyConstants;
@@ -204,6 +205,7 @@
                                 new MockSmartReplyInflater(),
                                 mock(NotifLayoutInflaterFactory.Provider.class),
                                 mock(HeadsUpStyleProvider.class),
+                                mock(PromotedNotificationContentExtractor.class),
                                 mock(NotificationRowContentBinderLogger.class))
                         : new NotificationContentInflater(
                                 mock(NotifRemoteViewCache.class),
@@ -214,6 +216,7 @@
                                 new MockSmartReplyInflater(),
                                 mock(NotifLayoutInflaterFactory.Provider.class),
                                 mock(HeadsUpStyleProvider.class),
+                                mock(PromotedNotificationContentExtractor.class),
                                 mock(NotificationRowContentBinderLogger.class));
         contentBinder.setInflateSynchronously(true);
         mBindStage = new RowContentBindStage(contentBinder,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
index 07935e4..92b8c3a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
@@ -24,8 +24,8 @@
 import com.android.systemui.flags.andSceneContainer
 import com.android.systemui.shade.transition.LargeScreenShadeInterpolator
 import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.notification.headsup.AvalancheController
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
-import com.android.systemui.statusbar.policy.AvalancheController
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index b8745b3..2eb4590 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -33,7 +33,6 @@
 import com.android.systemui.media.controls.ui.controller.KeyguardMediaController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
 import com.android.systemui.statusbar.notification.collection.render.MediaContainerController;
 import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -57,7 +56,6 @@
     @Mock private StatusBarStateController mStatusBarStateController;
     @Mock private ConfigurationController mConfigurationController;
     @Mock private KeyguardMediaController mKeyguardMediaController;
-    @Mock private NotificationSectionsFeatureManager mSectionsFeatureManager;
     @Mock private MediaContainerController mMediaContainerController;
     @Mock private NotificationRoundnessManager mNotificationRoundnessManager;
     @Mock private SectionHeaderController mIncomingHeaderController;
@@ -73,26 +71,10 @@
 
     @Before
     public void setUp() {
-        when(mSectionsFeatureManager.getNumberOfBuckets()).thenAnswer(
-                invocation -> {
-                    int count = 2;
-                    if (mSectionsFeatureManager.isFilteringEnabled()) {
-                        count = 5;
-                    }
-                    if (mSectionsFeatureManager.isMediaControlsEnabled()) {
-                        if (!mSectionsFeatureManager.isFilteringEnabled()) {
-                            count = 5;
-                        } else {
-                            count += 1;
-                        }
-                    }
-                    return count;
-                });
         mSectionsManager =
                 new NotificationSectionsManager(
                         mConfigurationController,
                         mKeyguardMediaController,
-                        mSectionsFeatureManager,
                         mMediaContainerController,
                         mNotificationRoundnessManager,
                         mIncomingHeaderController,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 6425da4..de40abb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -83,7 +83,7 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -107,7 +107,7 @@
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
 import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController;
 import com.android.systemui.statusbar.policy.ZenModeController;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index b877456..2b7e950 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -27,11 +27,11 @@
 import com.android.systemui.statusbar.notification.emptyshade.ui.view.EmptyShadeView
 import com.android.systemui.statusbar.notification.footer.ui.view.FooterView
 import com.android.systemui.statusbar.notification.footer.ui.view.FooterView.FooterViewState
+import com.android.systemui.statusbar.notification.headsup.AvalancheController
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
 import com.android.systemui.statusbar.notification.shared.NotificationsImprovedHunAnimation
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
-import com.android.systemui.statusbar.policy.AvalancheController
 import com.google.common.truth.Expect
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
index bf14472..e592e4b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
@@ -42,6 +42,7 @@
 import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs
 import com.android.systemui.statusbar.notification.emptyshade.shared.ModesEmptyShadeFix
 import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
+import com.android.systemui.statusbar.notification.headsup.PinnedStatus
 import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
 import com.android.systemui.statusbar.policy.data.repository.fakeUserSetupRepository
 import com.android.systemui.statusbar.policy.fakeConfigurationController
@@ -522,21 +523,21 @@
             assertThat(pinnedHeadsUpRows).isEmpty()
 
             // WHEN a row gets pinned
-            rows[0].isPinned.value = true
+            rows[0].pinnedStatus.value = PinnedStatus.PinnedBySystem
             runCurrent()
 
             // THEN it's added to the list
             assertThat(pinnedHeadsUpRows).containsExactly(rows[0])
 
             // WHEN more rows are pinned
-            rows[1].isPinned.value = true
+            rows[1].pinnedStatus.value = PinnedStatus.PinnedBySystem
             runCurrent()
 
             // THEN they are all in the list
             assertThat(pinnedHeadsUpRows).containsExactly(rows[0], rows[1])
 
             // WHEN a row gets unpinned
-            rows[0].isPinned.value = false
+            rows[0].pinnedStatus.value = PinnedStatus.NotPinned
             runCurrent()
 
             // THEN it's removed from the list
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 a940ed4..f48fd3c 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
@@ -838,27 +838,26 @@
         testScope.runTest {
             var notificationCount = 10
             val calculateSpace = { space: Float, useExtraShelfSpace: Boolean -> notificationCount }
-            val maxNotifications by collectLastValue(underTest.getMaxNotifications(calculateSpace))
+            val config by collectLastValue(underTest.getLockscreenDisplayConfig(calculateSpace))
             advanceTimeBy(50L)
             showLockscreen()
 
             shadeTestUtil.setSplitShade(false)
             configurationRepository.onAnyConfigurationChange()
 
-            assertThat(maxNotifications).isEqualTo(10)
+            assertThat(config?.maxNotifications).isEqualTo(10)
 
             // Also updates when directly requested (as it would from NotificationStackScrollLayout)
             notificationCount = 25
             sharedNotificationContainerInteractor.notificationStackChanged()
             advanceTimeBy(50L)
-            assertThat(maxNotifications).isEqualTo(25)
+            assertThat(config?.maxNotifications).isEqualTo(25)
 
             // Also ensure another collection starts with the same value. As an example, folding
             // then unfolding will restart the coroutine and it must get the last value immediately.
-            val newMaxNotifications by
-                collectLastValue(underTest.getMaxNotifications(calculateSpace))
+            val newConfig by collectLastValue(underTest.getLockscreenDisplayConfig(calculateSpace))
             advanceTimeBy(50L)
-            assertThat(newMaxNotifications).isEqualTo(25)
+            assertThat(newConfig?.maxNotifications).isEqualTo(25)
         }
 
     @Test
@@ -866,18 +865,18 @@
         testScope.runTest {
             var notificationCount = 10
             val calculateSpace = { space: Float, useExtraShelfSpace: Boolean -> notificationCount }
-            val maxNotifications by collectLastValue(underTest.getMaxNotifications(calculateSpace))
+            val config by collectLastValue(underTest.getLockscreenDisplayConfig(calculateSpace))
             advanceTimeBy(50L)
             showLockscreen()
 
             shadeTestUtil.setSplitShade(false)
             configurationRepository.onAnyConfigurationChange()
 
-            assertThat(maxNotifications).isEqualTo(10)
+            assertThat(config?.maxNotifications).isEqualTo(10)
 
             // Shade expanding... still 10
             shadeTestUtil.setLockscreenShadeExpansion(0.5f)
-            assertThat(maxNotifications).isEqualTo(10)
+            assertThat(config?.maxNotifications).isEqualTo(10)
 
             notificationCount = 25
 
@@ -885,20 +884,20 @@
             shadeTestUtil.setLockscreenShadeTracking(true)
 
             // Should still be 10, since the user is interacting
-            assertThat(maxNotifications).isEqualTo(10)
+            assertThat(config?.maxNotifications).isEqualTo(10)
 
             shadeTestUtil.setLockscreenShadeTracking(false)
             shadeTestUtil.setLockscreenShadeExpansion(0f)
 
             // Stopped tracking, show 25
-            assertThat(maxNotifications).isEqualTo(25)
+            assertThat(config?.maxNotifications).isEqualTo(25)
         }
 
     @Test
     fun maxNotificationsOnShade() =
         testScope.runTest {
             val calculateSpace = { space: Float, useExtraShelfSpace: Boolean -> 10 }
-            val maxNotifications by collectLastValue(underTest.getMaxNotifications(calculateSpace))
+            val config by collectLastValue(underTest.getLockscreenDisplayConfig(calculateSpace))
             advanceTimeBy(50L)
 
             // Show lockscreen with shade expanded
@@ -908,7 +907,7 @@
             configurationRepository.onAnyConfigurationChange()
 
             // -1 means No Limit
-            assertThat(maxNotifications).isEqualTo(-1)
+            assertThat(config?.maxNotifications).isEqualTo(-1)
         }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
index d9e9495..f76f1ce 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
@@ -57,7 +57,7 @@
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index 6441405..ad8b675 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -53,7 +53,7 @@
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index dd03ab3..f9f2cd3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -45,13 +45,14 @@
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor;
+import com.android.systemui.statusbar.notification.headsup.PinnedStatus;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation;
 import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.policy.Clock;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import org.junit.Assert;
@@ -131,13 +132,13 @@
 
     @Test
     public void testShowinEntryUpdated() {
-        mRow.setPinned(true);
+        mRow.setPinnedStatus(PinnedStatus.PinnedBySystem);
         when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
         when(mHeadsUpManager.getTopEntry()).thenReturn(mEntry);
         mHeadsUpAppearanceController.onHeadsUpPinned(mEntry);
         assertEquals(mRow.getEntry(), mHeadsUpStatusBarView.getShowingEntry());
 
-        mRow.setPinned(false);
+        mRow.setPinnedStatus(PinnedStatus.NotPinned);
         when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
         mHeadsUpAppearanceController.onHeadsUpUnPinned(mEntry);
         assertEquals(null, mHeadsUpStatusBarView.getShowingEntry());
@@ -145,13 +146,13 @@
 
     @Test
     public void testShownUpdated() {
-        mRow.setPinned(true);
+        mRow.setPinnedStatus(PinnedStatus.PinnedBySystem);
         when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
         when(mHeadsUpManager.getTopEntry()).thenReturn(mEntry);
         mHeadsUpAppearanceController.onHeadsUpPinned(mEntry);
         assertTrue(mHeadsUpAppearanceController.isShown());
 
-        mRow.setPinned(false);
+        mRow.setPinnedStatus(PinnedStatus.NotPinned);
         when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
         mHeadsUpAppearanceController.onHeadsUpUnPinned(mEntry);
         Assert.assertFalse(mHeadsUpAppearanceController.isShown());
@@ -160,13 +161,13 @@
     @Test
     @DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
     public void testHeaderUpdated() {
-        mRow.setPinned(true);
+        mRow.setPinnedStatus(PinnedStatus.PinnedBySystem);
         when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
         when(mHeadsUpManager.getTopEntry()).thenReturn(mEntry);
         mHeadsUpAppearanceController.onHeadsUpPinned(mEntry);
         assertEquals(mRow.getHeaderVisibleAmount(), 0.0f, 0.0f);
 
-        mRow.setPinned(false);
+        mRow.setPinnedStatus(PinnedStatus.NotPinned);
         when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
         mHeadsUpAppearanceController.onHeadsUpUnPinned(mEntry);
         assertEquals(mRow.getHeaderVisibleAmount(), 1.0f, 0.0f);
@@ -176,13 +177,13 @@
     public void testOperatorNameViewUpdated() {
         mHeadsUpAppearanceController.setAnimationsEnabled(false);
 
-        mRow.setPinned(true);
+        mRow.setPinnedStatus(PinnedStatus.PinnedBySystem);
         when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
         when(mHeadsUpManager.getTopEntry()).thenReturn(mEntry);
         mHeadsUpAppearanceController.onHeadsUpPinned(mEntry);
         assertEquals(View.INVISIBLE, mOperatorNameView.getVisibility());
 
-        mRow.setPinned(false);
+        mRow.setPinnedStatus(PinnedStatus.NotPinned);
         when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
         mHeadsUpAppearanceController.onHeadsUpUnPinned(mEntry);
         assertEquals(View.VISIBLE, mOperatorNameView.getVisibility());
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt
new file mode 100644
index 0000000..90506a1
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt
@@ -0,0 +1,73 @@
+/*
+ * 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.statusbar.phone
+
+import android.platform.test.annotations.EnableFlags
+import android.view.Display.DEFAULT_DISPLAY
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import com.android.systemui.testKosmos
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+class MultiDisplayAutoHideControllerStoreTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+    private val testScope = kosmos.testScope
+    private val fakeDisplayRepository = kosmos.displayRepository
+
+    // Lazy so that @EnableFlags has time to run before underTest is instantiated.
+    private val underTest by lazy { kosmos.multiDisplayAutoHideControllerStore }
+
+    @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) }
+
+    @Before
+    fun start() {
+        underTest.start()
+    }
+
+    @Test
+    fun beforeDisplayRemoved_doesNotStopInstances() =
+        testScope.runTest {
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+
+            verify(instance, never()).stop()
+        }
+
+    @Test
+    fun displayRemoved_stopsInstance() =
+        testScope.runTest {
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+
+            fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
+
+            verify(instance).stop()
+        }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ShadeTouchableRegionManagerTest.kt
similarity index 97%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ShadeTouchableRegionManagerTest.kt
index a008588..d82cb86 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ShadeTouchableRegionManagerTest.kt
@@ -41,12 +41,12 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 @OptIn(ExperimentalCoroutinesApi::class)
-class StatusBarTouchableRegionManagerTest : SysuiTestCase() {
+class ShadeTouchableRegionManagerTest : SysuiTestCase() {
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
     private val sceneRepository = kosmos.sceneContainerRepository
 
-    private val underTest by Lazy { kosmos.statusBarTouchableRegionManager }
+    private val underTest by Lazy { kosmos.shadeTouchableRegionManager }
 
     @Test
     @EnableSceneContainer
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 0eb6203..d174484 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -190,6 +190,8 @@
     private ArgumentCaptor<OnBackInvokedCallback> mBackCallbackCaptor;
     @Captor
     private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallback;
+    @Mock
+    private KeyguardDismissActionInteractor mKeyguardDismissActionInteractor;
 
     @Rule
     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@@ -236,7 +238,7 @@
                         mKeyguardTransitionInteractor,
                         mock(KeyguardDismissTransitionInteractor.class),
                         StandardTestDispatcher(null, null),
-                        () -> mock(KeyguardDismissActionInteractor.class),
+                        () -> mKeyguardDismissActionInteractor,
                         mSelectedUserInteractor,
                         mock(JavaAdapter.class),
                         () -> mSceneInteractor,
@@ -968,4 +970,33 @@
         );
         verify(mAlternateBouncerInteractor).hide();
     }
+
+    @Test
+    public void hideAlternateBouncer_clearsDismissActionByDefault() {
+        clearInvocations(mKeyguardDismissActionInteractor);
+
+        mStatusBarKeyguardViewManager.hideAlternateBouncer(/* updateScrim= */ true);
+
+        verify(mKeyguardDismissActionInteractor).clearDismissAction();
+    }
+
+    @Test
+    public void hideAlternateBouncer_clearsDismissActionExplicitly() {
+        clearInvocations(mKeyguardDismissActionInteractor);
+
+        mStatusBarKeyguardViewManager.hideAlternateBouncer(
+                /* updateScrim= */ true, /* clearDismissAction= */ true);
+
+        verify(mKeyguardDismissActionInteractor).clearDismissAction();
+    }
+
+    @Test
+    public void hideAlternateBouncer_doNotClearDismissActionExplicitly() {
+        clearInvocations(mKeyguardDismissActionInteractor);
+
+        mStatusBarKeyguardViewManager.hideAlternateBouncer(
+                /* updateScrim= */ true, /* clearDismissAction= */ false);
+
+        verify(mKeyguardDismissActionInteractor, never()).clearDismissAction();
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index 95472cad..41782a1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -73,7 +73,7 @@
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/data/repository/KeyguardBypassRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/data/repository/KeyguardBypassRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/data/repository/KeyguardBypassRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/data/repository/KeyguardBypassRepositoryTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
index b9cdd06..7b04fc8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
@@ -28,8 +28,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.coroutines.collectValues
 import com.android.systemui.flags.DisableSceneContainer
 import com.android.systemui.flags.EnableSceneContainer
 import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
@@ -39,7 +37,9 @@
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.testCase
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.collectValues
+import com.android.systemui.kosmos.runTest
 import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.log.assertLogsWtf
@@ -52,6 +52,7 @@
 import com.android.systemui.shade.shadeTestUtil
 import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.NORMAL_PACKAGE
 import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.setUpPackageManagerForMediaProjection
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
 import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsScreenRecordChip
 import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsShareToAppChip
@@ -66,15 +67,17 @@
 import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.Idle
 import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
 import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
+import com.android.systemui.statusbar.notification.data.repository.FakeHeadsUpRowRepository
 import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
 import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
 import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
+import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
 import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.HomeStatusBarViewModel.VisibilityModel
+import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.emptyFlow
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -83,35 +86,22 @@
 @OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(AndroidJUnit4::class)
 class HomeStatusBarViewModelImplTest : SysuiTestCase() {
-    private val kosmos =
-        Kosmos().also {
-            it.testCase = this
-            it.testDispatcher = UnconfinedTestDispatcher()
-        }
-
-    private val testScope = kosmos.testScope
-
-    private val statusBarModeRepository = kosmos.fakeStatusBarModeRepository
-    private val activeNotificationListRepository = kosmos.activeNotificationListRepository
-    private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
-    private val disableFlagsRepository = kosmos.fakeDisableFlagsRepository
-    private val systemStatusEventAnimationRepository = kosmos.systemStatusEventAnimationRepository
-
-    private lateinit var underTest: HomeStatusBarViewModel
+    private val kosmos by lazy {
+        testKosmos().also { it.testDispatcher = UnconfinedTestDispatcher() }
+    }
+    private val Kosmos.underTest by Kosmos.Fixture { kosmos.homeStatusBarViewModel }
 
     @Before
     fun setUp() {
         setUpPackageManagerForMediaProjection(kosmos)
-        // Initialize here because some flags are checked when this class is constructed
-        underTest = kosmos.homeStatusBarViewModel
     }
 
     @Test
     fun isTransitioningFromLockscreenToOccluded_started_isTrue() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isTransitioningFromLockscreenToOccluded)
 
-            keyguardTransitionRepository.sendTransitionStep(
+            fakeKeyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     KeyguardState.LOCKSCREEN,
                     KeyguardState.OCCLUDED,
@@ -125,10 +115,10 @@
 
     @Test
     fun isTransitioningFromLockscreenToOccluded_running_isTrue() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isTransitioningFromLockscreenToOccluded)
 
-            keyguardTransitionRepository.sendTransitionStep(
+            fakeKeyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     KeyguardState.LOCKSCREEN,
                     KeyguardState.OCCLUDED,
@@ -142,10 +132,10 @@
 
     @Test
     fun isTransitioningFromLockscreenToOccluded_finished_isFalse() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isTransitioningFromLockscreenToOccluded)
 
-            keyguardTransitionRepository.sendTransitionSteps(
+            fakeKeyguardTransitionRepository.sendTransitionSteps(
                 from = KeyguardState.LOCKSCREEN,
                 to = KeyguardState.OCCLUDED,
                 testScope.testScheduler,
@@ -156,10 +146,10 @@
 
     @Test
     fun isTransitioningFromLockscreenToOccluded_canceled_isFalse() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isTransitioningFromLockscreenToOccluded)
 
-            keyguardTransitionRepository.sendTransitionStep(
+            fakeKeyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     KeyguardState.LOCKSCREEN,
                     KeyguardState.OCCLUDED,
@@ -173,10 +163,10 @@
 
     @Test
     fun isTransitioningFromLockscreenToOccluded_irrelevantTransition_isFalse() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isTransitioningFromLockscreenToOccluded)
 
-            keyguardTransitionRepository.sendTransitionStep(
+            fakeKeyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     KeyguardState.AOD,
                     KeyguardState.LOCKSCREEN,
@@ -190,10 +180,10 @@
 
     @Test
     fun isTransitioningFromLockscreenToOccluded_followsRepoUpdates() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isTransitioningFromLockscreenToOccluded)
 
-            keyguardTransitionRepository.sendTransitionStep(
+            fakeKeyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     KeyguardState.LOCKSCREEN,
                     KeyguardState.OCCLUDED,
@@ -205,7 +195,7 @@
             assertThat(latest).isTrue()
 
             // WHEN the repo updates the transition to finished
-            keyguardTransitionRepository.sendTransitionStep(
+            fakeKeyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     KeyguardState.LOCKSCREEN,
                     KeyguardState.OCCLUDED,
@@ -220,10 +210,10 @@
 
     @Test
     fun transitionFromLockscreenToDreamStartedEvent_started_emitted() =
-        testScope.runTest {
+        kosmos.runTest {
             val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
 
-            keyguardTransitionRepository.sendTransitionStep(
+            fakeKeyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     KeyguardState.LOCKSCREEN,
                     KeyguardState.DREAMING,
@@ -237,10 +227,10 @@
 
     @Test
     fun transitionFromLockscreenToDreamStartedEvent_startedMultiple_emittedMultiple() =
-        testScope.runTest {
+        kosmos.runTest {
             val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
 
-            keyguardTransitionRepository.sendTransitionStep(
+            fakeKeyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     KeyguardState.LOCKSCREEN,
                     KeyguardState.DREAMING,
@@ -249,7 +239,7 @@
                 )
             )
 
-            keyguardTransitionRepository.sendTransitionStep(
+            fakeKeyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     KeyguardState.LOCKSCREEN,
                     KeyguardState.DREAMING,
@@ -258,7 +248,7 @@
                 )
             )
 
-            keyguardTransitionRepository.sendTransitionStep(
+            fakeKeyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     KeyguardState.LOCKSCREEN,
                     KeyguardState.DREAMING,
@@ -272,10 +262,10 @@
 
     @Test
     fun transitionFromLockscreenToDreamStartedEvent_startedThenRunning_emittedOnlyOne() =
-        testScope.runTest {
+        kosmos.runTest {
             val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
 
-            keyguardTransitionRepository.sendTransitionStep(
+            fakeKeyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     KeyguardState.LOCKSCREEN,
                     KeyguardState.DREAMING,
@@ -287,7 +277,7 @@
 
             // WHEN the transition progresses through its animation by going through the RUNNING
             // step with increasing fractions
-            keyguardTransitionRepository.sendTransitionStep(
+            fakeKeyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     KeyguardState.LOCKSCREEN,
                     KeyguardState.DREAMING,
@@ -296,7 +286,7 @@
                 )
             )
 
-            keyguardTransitionRepository.sendTransitionStep(
+            fakeKeyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     KeyguardState.LOCKSCREEN,
                     KeyguardState.DREAMING,
@@ -305,7 +295,7 @@
                 )
             )
 
-            keyguardTransitionRepository.sendTransitionStep(
+            fakeKeyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     KeyguardState.LOCKSCREEN,
                     KeyguardState.DREAMING,
@@ -321,10 +311,10 @@
 
     @Test
     fun transitionFromLockscreenToDreamStartedEvent_irrelevantTransition_notEmitted() =
-        testScope.runTest {
+        kosmos.runTest {
             val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
 
-            keyguardTransitionRepository.sendTransitionStep(
+            fakeKeyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     KeyguardState.LOCKSCREEN,
                     KeyguardState.OCCLUDED,
@@ -338,10 +328,10 @@
 
     @Test
     fun transitionFromLockscreenToDreamStartedEvent_irrelevantTransitionState_notEmitted() =
-        testScope.runTest {
+        kosmos.runTest {
             val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
 
-            keyguardTransitionRepository.sendTransitionStep(
+            fakeKeyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     KeyguardState.LOCKSCREEN,
                     KeyguardState.DREAMING,
@@ -359,8 +349,8 @@
     @Test
     @EnableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
     fun areNotificationsLightsOut_lowProfileWithNotifications_true() =
-        testScope.runTest {
-            statusBarModeRepository.defaultDisplay.statusBarMode.value =
+        kosmos.runTest {
+            fakeStatusBarModeRepository.defaultDisplay.statusBarMode.value =
                 StatusBarMode.LIGHTS_OUT_TRANSPARENT
             activeNotificationListRepository.activeNotifications.value =
                 activeNotificationsStore(testNotifications)
@@ -373,8 +363,8 @@
     @Test
     @EnableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
     fun areNotificationsLightsOut_lowProfileWithoutNotifications_false() =
-        testScope.runTest {
-            statusBarModeRepository.defaultDisplay.statusBarMode.value =
+        kosmos.runTest {
+            fakeStatusBarModeRepository.defaultDisplay.statusBarMode.value =
                 StatusBarMode.LIGHTS_OUT_TRANSPARENT
             activeNotificationListRepository.activeNotifications.value =
                 activeNotificationsStore(emptyList())
@@ -387,8 +377,9 @@
     @Test
     @EnableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
     fun areNotificationsLightsOut_defaultStatusBarModeWithoutNotifications_false() =
-        testScope.runTest {
-            statusBarModeRepository.defaultDisplay.statusBarMode.value = StatusBarMode.TRANSPARENT
+        kosmos.runTest {
+            fakeStatusBarModeRepository.defaultDisplay.statusBarMode.value =
+                StatusBarMode.TRANSPARENT
             activeNotificationListRepository.activeNotifications.value =
                 activeNotificationsStore(emptyList())
 
@@ -400,8 +391,9 @@
     @Test
     @EnableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
     fun areNotificationsLightsOut_defaultStatusBarModeWithNotifications_false() =
-        testScope.runTest {
-            statusBarModeRepository.defaultDisplay.statusBarMode.value = StatusBarMode.TRANSPARENT
+        kosmos.runTest {
+            fakeStatusBarModeRepository.defaultDisplay.statusBarMode.value =
+                StatusBarMode.TRANSPARENT
             activeNotificationListRepository.activeNotifications.value =
                 activeNotificationsStore(testNotifications)
 
@@ -413,7 +405,7 @@
     @Test
     @DisableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
     fun areNotificationsLightsOut_requiresFlagEnabled() =
-        testScope.runTest {
+        kosmos.runTest {
             assertLogsWtf {
                 val flow = underTest.areNotificationsLightsOut(DISPLAY_ID)
                 assertThat(flow).isEqualTo(emptyFlow<Boolean>())
@@ -422,7 +414,7 @@
 
     @Test
     fun primaryOngoingActivityChip_matchesViewModel() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.primaryOngoingActivityChip)
 
             kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording
@@ -441,7 +433,7 @@
 
     @Test
     fun isHomeStatusBarAllowedByScene_sceneLockscreen_notOccluded_false() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
@@ -452,7 +444,7 @@
 
     @Test
     fun isHomeStatusBarAllowedByScene_sceneLockscreen_occluded_true() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
@@ -463,7 +455,7 @@
 
     @Test
     fun isHomeStatusBarAllowedByScene_sceneBouncer_false() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Bouncer)
@@ -473,7 +465,7 @@
 
     @Test
     fun isHomeStatusBarAllowedByScene_sceneCommunal_false() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Communal)
@@ -483,7 +475,7 @@
 
     @Test
     fun isHomeStatusBarAllowedByScene_sceneShade_false() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Shade)
@@ -493,7 +485,7 @@
 
     @Test
     fun isHomeStatusBarAllowedByScene_sceneGone_true() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Gone)
@@ -503,35 +495,91 @@
 
     @Test
     fun isClockVisible_allowedByDisableFlags_visible() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isClockVisible)
             transitionKeyguardToGone()
 
-            disableFlagsRepository.disableFlags.value =
+            fakeDisableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)
 
             assertThat(latest!!.visibility).isEqualTo(View.VISIBLE)
         }
 
     @Test
-    fun isClockVisible_notAllowedByDisableFlags_gone() =
-        testScope.runTest {
+    fun isClockVisible_notAllowedByDisableFlags_invisible() =
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isClockVisible)
             transitionKeyguardToGone()
 
-            disableFlagsRepository.disableFlags.value =
+            fakeDisableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(DISABLE_CLOCK, DISABLE2_NONE)
 
-            assertThat(latest!!.visibility).isEqualTo(View.GONE)
+            assertThat(latest!!.visibility).isEqualTo(View.INVISIBLE)
+        }
+
+    @Test
+    fun isClockVisible_allowedByFlags_hunActive_notVisible() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isClockVisible)
+            transitionKeyguardToGone()
+
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)
+            // there is an active HUN
+            headsUpNotificationRepository.setNotifications(
+                fakeHeadsUpRowRepository(isPinned = true)
+            )
+
+            assertThat(latest!!.visibility).isEqualTo(View.INVISIBLE)
+        }
+
+    @Test
+    fun isClockVisible_allowedByFlags_hunBecomesInactive_visibleAgain() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isClockVisible)
+            transitionKeyguardToGone()
+
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)
+            // there is an active HUN
+            headsUpNotificationRepository.setNotifications(
+                fakeHeadsUpRowRepository(isPinned = true)
+            )
+
+            // hun goes away
+            headsUpNotificationRepository.setNotifications(listOf())
+
+            assertThat(latest!!.visibility).isEqualTo(View.VISIBLE)
+        }
+
+    @Test
+    fun isClockVisible_disabledByFlags_hunBecomesInactive_neverVisible() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isClockVisible)
+            transitionKeyguardToGone()
+
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(DISABLE_CLOCK, DISABLE2_NONE)
+            // there is an active HUN
+            headsUpNotificationRepository.setNotifications(
+                fakeHeadsUpRowRepository(isPinned = true)
+            )
+
+            assertThat(latest!!.visibility).isEqualTo(View.INVISIBLE)
+
+            // hun goes away
+            headsUpNotificationRepository.setNotifications(listOf())
+
+            assertThat(latest!!.visibility).isEqualTo(View.INVISIBLE)
         }
 
     @Test
     fun isNotificationIconContainerVisible_allowedByDisableFlags_visible() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isNotificationIconContainerVisible)
             transitionKeyguardToGone()
 
-            disableFlagsRepository.disableFlags.value =
+            fakeDisableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)
 
             assertThat(latest!!.visibility).isEqualTo(View.VISIBLE)
@@ -539,23 +587,55 @@
 
     @Test
     fun isNotificationIconContainerVisible_notAllowedByDisableFlags_gone() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isNotificationIconContainerVisible)
             transitionKeyguardToGone()
 
-            disableFlagsRepository.disableFlags.value =
+            fakeDisableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(DISABLE_NOTIFICATION_ICONS, DISABLE2_NONE)
 
             assertThat(latest!!.visibility).isEqualTo(View.GONE)
         }
 
     @Test
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+    fun isNotificationIconContainerVisible_anyChipShowing_PromotedNotifsOn() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isNotificationIconContainerVisible)
+            transitionKeyguardToGone()
+
+            kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording
+
+            assertThat(latest!!.visibility).isEqualTo(View.GONE)
+
+            kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.DoingNothing
+
+            assertThat(latest!!.visibility).isEqualTo(View.VISIBLE)
+        }
+
+    @Test
+    @DisableFlags(StatusBarNotifChips.FLAG_NAME)
+    fun isNotificationIconContainerVisible_anyChipShowing_PromotedNotifsOff() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isNotificationIconContainerVisible)
+            transitionKeyguardToGone()
+
+            kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording
+
+            assertThat(latest!!.visibility).isEqualTo(View.GONE)
+
+            kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.DoingNothing
+
+            assertThat(latest!!.visibility).isEqualTo(View.VISIBLE)
+        }
+
+    @Test
     fun isSystemInfoVisible_allowedByDisableFlags_visible() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.systemInfoCombinedVis)
             transitionKeyguardToGone()
 
-            disableFlagsRepository.disableFlags.value =
+            fakeDisableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)
 
             assertThat(latest!!.baseVisibility.visibility).isEqualTo(View.VISIBLE)
@@ -563,11 +643,11 @@
 
     @Test
     fun isSystemInfoVisible_notAllowedByDisableFlags_gone() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.systemInfoCombinedVis)
             transitionKeyguardToGone()
 
-            disableFlagsRepository.disableFlags.value =
+            fakeDisableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(DISABLE_SYSTEM_INFO, DISABLE2_NONE)
 
             assertThat(latest!!.baseVisibility.visibility).isEqualTo(View.GONE)
@@ -575,7 +655,7 @@
 
     @Test
     fun systemInfoCombineVis_animationsPassThrough() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.systemInfoCombinedVis)
             transitionKeyguardToGone()
 
@@ -601,18 +681,18 @@
     @Test
     @DisableSceneContainer
     fun lockscreenVisible_sceneFlagOff_noStatusBarViewsShown() =
-        testScope.runTest {
+        kosmos.runTest {
             val clockVisible by collectLastValue(underTest.isClockVisible)
             val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
             val systemInfoVisible by collectLastValue(underTest.systemInfoCombinedVis)
 
-            keyguardTransitionRepository.sendTransitionSteps(
+            fakeKeyguardTransitionRepository.sendTransitionSteps(
                 from = KeyguardState.GONE,
                 to = KeyguardState.LOCKSCREEN,
-                testScope = this,
+                testScope = testScope,
             )
 
-            assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+            assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE)
             assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
             assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE)
         }
@@ -620,14 +700,14 @@
     @Test
     @EnableSceneContainer
     fun lockscreenVisible_sceneFlagOn_noStatusBarViewsShown() =
-        testScope.runTest {
+        kosmos.runTest {
             val clockVisible by collectLastValue(underTest.isClockVisible)
             val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
             val systemInfoVisible by collectLastValue(underTest.systemInfoCombinedVis)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
 
-            assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+            assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE)
             assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
             assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE)
         }
@@ -635,18 +715,18 @@
     @Test
     @DisableSceneContainer
     fun bouncerVisible_sceneFlagOff_noStatusBarViewsShown() =
-        testScope.runTest {
+        kosmos.runTest {
             val clockVisible by collectLastValue(underTest.isClockVisible)
             val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
             val systemInfoVisible by collectLastValue(underTest.systemInfoCombinedVis)
 
-            keyguardTransitionRepository.sendTransitionSteps(
+            fakeKeyguardTransitionRepository.sendTransitionSteps(
                 from = KeyguardState.LOCKSCREEN,
                 to = KeyguardState.PRIMARY_BOUNCER,
-                testScope = this,
+                testScope = testScope,
             )
 
-            assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+            assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE)
             assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
             assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE)
         }
@@ -654,14 +734,14 @@
     @Test
     @EnableSceneContainer
     fun bouncerVisible_sceneFlagOn_noStatusBarViewsShown() =
-        testScope.runTest {
+        kosmos.runTest {
             val clockVisible by collectLastValue(underTest.isClockVisible)
             val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
             val systemInfoVisible by collectLastValue(underTest.systemInfoCombinedVis)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Bouncer)
 
-            assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+            assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE)
             assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
             assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE)
         }
@@ -669,15 +749,15 @@
     @Test
     @DisableSceneContainer
     fun keyguardIsOccluded_sceneFlagOff_statusBarViewsShown() =
-        testScope.runTest {
+        kosmos.runTest {
             val clockVisible by collectLastValue(underTest.isClockVisible)
             val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
             val systemInfoVisible by collectLastValue(underTest.systemInfoCombinedVis)
 
-            keyguardTransitionRepository.sendTransitionSteps(
+            fakeKeyguardTransitionRepository.sendTransitionSteps(
                 from = KeyguardState.LOCKSCREEN,
                 to = KeyguardState.OCCLUDED,
-                testScope = this,
+                testScope = testScope,
             )
 
             assertThat(clockVisible!!.visibility).isEqualTo(View.VISIBLE)
@@ -688,7 +768,7 @@
     @Test
     @EnableSceneContainer
     fun keyguardIsOccluded_sceneFlagOn_statusBarViewsShown() =
-        testScope.runTest {
+        kosmos.runTest {
             val clockVisible by collectLastValue(underTest.isClockVisible)
             val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
             val systemInfoVisible by collectLastValue(underTest.systemInfoCombinedVis)
@@ -704,7 +784,7 @@
     @Test
     @DisableSceneContainer
     fun keyguardNotShown_sceneFlagOff_statusBarViewsShown() =
-        testScope.runTest {
+        kosmos.runTest {
             val clockVisible by collectLastValue(underTest.isClockVisible)
             val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
             val systemInfoVisible by collectLastValue(underTest.systemInfoCombinedVis)
@@ -719,7 +799,7 @@
     @Test
     @DisableSceneContainer
     fun shadeNotShown_sceneFlagOff_statusBarViewsShown() =
-        testScope.runTest {
+        kosmos.runTest {
             val clockVisible by collectLastValue(underTest.isClockVisible)
             val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
             val systemInfoVisible by collectLastValue(underTest.systemInfoCombinedVis)
@@ -735,7 +815,7 @@
     @Test
     @EnableSceneContainer
     fun keyguardNotShownAndShadeNotShown_sceneFlagOn_statusBarViewsShown() =
-        testScope.runTest {
+        kosmos.runTest {
             val clockVisible by collectLastValue(underTest.isClockVisible)
             val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
             val systemInfoVisible by collectLastValue(underTest.systemInfoCombinedVis)
@@ -750,7 +830,7 @@
     @Test
     @DisableSceneContainer
     fun shadeShown_sceneFlagOff_noStatusBarViewsShown() =
-        testScope.runTest {
+        kosmos.runTest {
             val clockVisible by collectLastValue(underTest.isClockVisible)
             val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
             val systemInfoVisible by collectLastValue(underTest.systemInfoCombinedVis)
@@ -758,7 +838,7 @@
 
             kosmos.shadeTestUtil.setShadeExpansion(1f)
 
-            assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+            assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE)
             assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
             assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE)
         }
@@ -766,7 +846,7 @@
     @Test
     @EnableSceneContainer
     fun shadeShown_sceneFlagOn_noStatusBarViewsShown() =
-        testScope.runTest {
+        kosmos.runTest {
             val clockVisible by collectLastValue(underTest.isClockVisible)
             val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
             val systemInfoVisible by collectLastValue(underTest.systemInfoCombinedVis)
@@ -774,7 +854,7 @@
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Shade)
 
-            assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+            assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE)
             assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
             assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE)
         }
@@ -782,20 +862,20 @@
     @Test
     @DisableSceneContainer
     fun secureCameraActive_sceneFlagOff_noStatusBarViewsShown() =
-        testScope.runTest {
+        kosmos.runTest {
             val clockVisible by collectLastValue(underTest.isClockVisible)
             val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
             val systemInfoVisible by collectLastValue(underTest.systemInfoCombinedVis)
 
             // Secure camera is an occluding activity
-            keyguardTransitionRepository.sendTransitionSteps(
+            fakeKeyguardTransitionRepository.sendTransitionSteps(
                 from = KeyguardState.LOCKSCREEN,
                 to = KeyguardState.OCCLUDED,
-                testScope = this,
+                testScope = testScope,
             )
             kosmos.keyguardInteractor.onCameraLaunchDetected(CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP)
 
-            assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+            assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE)
             assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
             assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE)
         }
@@ -803,7 +883,7 @@
     @Test
     @EnableSceneContainer
     fun secureCameraActive_sceneFlagOn_noStatusBarViewsShown() =
-        testScope.runTest {
+        kosmos.runTest {
             val clockVisible by collectLastValue(underTest.isClockVisible)
             val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
             val systemInfoVisible by collectLastValue(underTest.systemInfoCombinedVis)
@@ -813,21 +893,26 @@
             kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(true, taskInfo = null)
             kosmos.keyguardInteractor.onCameraLaunchDetected(CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP)
 
-            assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+            assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE)
             assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
             assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE)
         }
 
+    // Cribbed from [HeadsUpNotificationInteractorTest.kt]
+    private fun fakeHeadsUpRowRepository(key: String = "test key", isPinned: Boolean = false) =
+        FakeHeadsUpRowRepository(key = key, isPinned = isPinned)
+
     private fun activeNotificationsStore(notifications: List<ActiveNotificationModel>) =
         ActiveNotificationsStore.Builder()
             .apply { notifications.forEach(::addIndividualNotif) }
             .build()
 
-    private val testNotifications =
+    private val testNotifications by lazy {
         listOf(activeNotificationModel(key = "notif1"), activeNotificationModel(key = "notif2"))
+    }
 
-    private suspend fun transitionKeyguardToGone() {
-        keyguardTransitionRepository.sendTransitionSteps(
+    private suspend fun Kosmos.transitionKeyguardToGone() {
+        fakeKeyguardTransitionRepository.sendTransitionSteps(
             from = KeyguardState.LOCKSCREEN,
             to = KeyguardState.GONE,
             testScope = testScope,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/glowboxeffect/GlowBoxEffectTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/glowboxeffect/GlowBoxEffectTest.kt
index 32ef501..09ea767 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/glowboxeffect/GlowBoxEffectTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/glowboxeffect/GlowBoxEffectTest.kt
@@ -90,15 +90,15 @@
 
         assertThat(glowBoxEffect.state).isEqualTo(GlowBoxEffect.AnimationState.EASE_IN)
 
-        animatorTestRule.advanceTimeBy(config.easeInDuration + 50L)
+        animatorTestRule.advanceAnimationDuration(config.easeInDuration + 50L)
 
         assertThat(glowBoxEffect.state).isEqualTo(GlowBoxEffect.AnimationState.MAIN)
 
-        animatorTestRule.advanceTimeBy(config.duration + 50L)
+        animatorTestRule.advanceAnimationDuration(config.duration + 50L)
 
         assertThat(glowBoxEffect.state).isEqualTo(GlowBoxEffect.AnimationState.EASE_OUT)
 
-        animatorTestRule.advanceTimeBy(config.easeOutDuration + 50L)
+        animatorTestRule.advanceAnimationDuration(config.easeOutDuration + 50L)
 
         assertThat(glowBoxEffect.state).isEqualTo(GlowBoxEffect.AnimationState.NOT_PLAYING)
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt
index 67a4219..c9be7e3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt
@@ -117,9 +117,9 @@
         loadingEffect.play()
 
         // Execute all the animators by advancing each duration with some buffer.
-        animatorTestRule.advanceTimeBy(config.easeInDuration.toLong())
-        animatorTestRule.advanceTimeBy(config.maxDuration.toLong())
-        animatorTestRule.advanceTimeBy(config.easeOutDuration.toLong())
+        animatorTestRule.advanceAnimationDuration(config.easeInDuration.toLong())
+        animatorTestRule.advanceAnimationDuration(config.maxDuration.toLong())
+        animatorTestRule.advanceAnimationDuration(config.easeOutDuration.toLong())
         animatorTestRule.advanceTimeBy(500)
 
         assertThat(states)
@@ -206,12 +206,12 @@
         assertThat(isFinished).isFalse()
 
         loadingEffect.play()
-        animatorTestRule.advanceTimeBy(config.easeInDuration.toLong() + 500L)
+        animatorTestRule.advanceAnimationDuration(config.easeInDuration.toLong() + 500L)
 
         assertThat(isFinished).isFalse()
 
         loadingEffect.finish()
-        animatorTestRule.advanceTimeBy(config.easeOutDuration.toLong() + 500L)
+        animatorTestRule.advanceAnimationDuration(config.easeOutDuration.toLong() + 500L)
 
         assertThat(isFinished).isTrue()
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureRecognizerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureRecognizerTest.kt
index 7d3ed92..7aa389a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureRecognizerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureRecognizerTest.kt
@@ -20,10 +20,12 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.testKosmos
 import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.Finished
 import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.InProgress
 import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.NotStarted
 import com.android.systemui.touchpad.tutorial.ui.gesture.MultiFingerGesture.Companion.SWIPE_DISTANCE
+import com.android.systemui.touchpad.ui.gesture.fakeVelocityTracker
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
@@ -33,12 +35,24 @@
 @RunWith(AndroidJUnit4::class)
 class HomeGestureRecognizerTest : SysuiTestCase() {
 
+    companion object {
+        const val THRESHOLD_VELOCITY_PX_PER_MS = 1f
+        const val SLOW = THRESHOLD_VELOCITY_PX_PER_MS - 0.01f
+        const val FAST = THRESHOLD_VELOCITY_PX_PER_MS + 0.01f
+    }
+
     private var gestureState: GestureState = GestureState.NotStarted
+    private var velocityTracker = testKosmos().fakeVelocityTracker
     private val gestureRecognizer =
-        HomeGestureRecognizer(gestureDistanceThresholdPx = SWIPE_DISTANCE.toInt())
+        HomeGestureRecognizer(
+            gestureDistanceThresholdPx = SWIPE_DISTANCE.toInt(),
+            velocityThresholdPxPerMs = THRESHOLD_VELOCITY_PX_PER_MS,
+            velocityTracker = velocityTracker,
+        )
 
     @Before
     fun before() {
+        velocityTracker.setVelocity(Velocity(FAST))
         gestureRecognizer.addGestureStateCallback { gestureState = it }
     }
 
@@ -48,6 +62,12 @@
     }
 
     @Test
+    fun doesntTriggerGestureFinished_onGestureSpeedTooSlow() {
+        velocityTracker.setVelocity(Velocity(SLOW))
+        assertStateAfterEvents(events = ThreeFingerGesture.swipeUp(), expectedState = NotStarted)
+    }
+
+    @Test
     fun triggersGestureProgressForThreeFingerGestureStarted() {
         assertStateAfterEvents(
             events = ThreeFingerGesture.startEvents(x = 0f, y = 0f),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureRecognizerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureRecognizerTest.kt
index c5c0d59..cb74e65 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureRecognizerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureRecognizerTest.kt
@@ -17,21 +17,19 @@
 package com.android.systemui.touchpad.tutorial.ui.gesture
 
 import android.view.MotionEvent
-import androidx.compose.ui.input.pointer.util.VelocityTracker1D
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.testKosmos
 import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.Finished
 import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.InProgress
 import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.NotStarted
 import com.android.systemui.touchpad.tutorial.ui.gesture.MultiFingerGesture.Companion.SWIPE_DISTANCE
+import com.android.systemui.touchpad.ui.gesture.fakeVelocityTracker
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.kotlin.doReturn
-import org.mockito.kotlin.mock
-import org.mockito.kotlin.whenever
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
@@ -39,26 +37,23 @@
 
     companion object {
         const val THRESHOLD_VELOCITY_PX_PER_MS = 0.1f
-        // multiply by 1000 to get px/ms instead of px/s which is unit used by velocity tracker
-        const val SLOW = THRESHOLD_VELOCITY_PX_PER_MS * 1000 - 1
-        const val FAST = THRESHOLD_VELOCITY_PX_PER_MS * 1000 + 1
+        const val SLOW = THRESHOLD_VELOCITY_PX_PER_MS - 0.01f
+        const val FAST = THRESHOLD_VELOCITY_PX_PER_MS + 0.01f
     }
 
+    private var velocityTracker = testKosmos().fakeVelocityTracker
+
     private var gestureState: GestureState = GestureState.NotStarted
-    private val velocityTracker1D =
-        mock<VelocityTracker1D> {
-            // by default return correct speed for the gesture - as if pointer is slowing down
-            on { calculateVelocity() } doReturn SLOW
-        }
     private val gestureRecognizer =
         RecentAppsGestureRecognizer(
             gestureDistanceThresholdPx = SWIPE_DISTANCE.toInt(),
             velocityThresholdPxPerMs = THRESHOLD_VELOCITY_PX_PER_MS,
-            velocityTracker = VerticalVelocityTracker(velocityTracker1D),
+            velocityTracker = velocityTracker,
         )
 
     @Before
     fun before() {
+        velocityTracker.setVelocity(Velocity(SLOW))
         gestureRecognizer.addGestureStateCallback { gestureState = it }
     }
 
@@ -69,7 +64,7 @@
 
     @Test
     fun doesntTriggerGestureFinished_onGestureSpeedTooHigh() {
-        whenever(velocityTracker1D.calculateVelocity()).thenReturn(FAST)
+        velocityTracker.setVelocity(Velocity(FAST))
         assertStateAfterEvents(events = ThreeFingerGesture.swipeUp(), expectedState = NotStarted)
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt
index 266a60d..665f55b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt
@@ -193,7 +193,11 @@
         }
 
     private fun TestScope.advanceTime(timeMs: Long) {
-        animatorTestRule.advanceTimeBy(timeMs)
+        if (timeMs == ANIMATION_DURATION) {
+            animatorTestRule.advanceAnimationDuration(timeMs)
+        } else {
+            animatorTestRule.advanceTimeBy(timeMs)
+        }
         advanceTimeBy(timeMs)
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
index 20b273a..d5651ec 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
@@ -22,21 +22,25 @@
 import android.content.pm.UserInfo
 import android.os.UserHandle
 import android.os.UserManager
+import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.GuestResetOrExitSessionReceiver
 import com.android.systemui.GuestResumeSessionReceiver
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.testKosmos
 import com.android.systemui.user.data.repository.FakeUserRepository
 import com.android.systemui.user.domain.model.ShowDialogRequestModel
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.kotlinArgumentCaptor
 import com.android.systemui.util.mockito.whenever
 import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.test.TestCoroutineScope
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -48,6 +52,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper
 class GuestUserInteractorTest : SysuiTestCase() {
 
     @Mock private lateinit var manager: UserManager
@@ -64,16 +69,15 @@
 
     private lateinit var underTest: GuestUserInteractor
 
-    private lateinit var scope: TestCoroutineScope
-    private lateinit var repository: FakeUserRepository
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+    private val scope = kosmos.testScope
+    private val repository = FakeUserRepository()
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         whenever(manager.createGuest(any())).thenReturn(GUEST_USER_INFO)
 
-        scope = TestCoroutineScope()
-        repository = FakeUserRepository()
         repository.setUserInfos(ALL_USERS)
 
         underTest = initGuestUserInteractor(context)
@@ -83,8 +87,8 @@
         GuestUserInteractor(
             applicationContext = context,
             applicationScope = scope,
-            mainDispatcher = IMMEDIATE,
-            backgroundDispatcher = IMMEDIATE,
+            mainDispatcher = kosmos.testDispatcher,
+            backgroundDispatcher = kosmos.testDispatcher,
             manager = manager,
             repository = repository,
             deviceProvisionedController = deviceProvisionedController,
@@ -92,7 +96,7 @@
             refreshUsersScheduler =
                 RefreshUsersScheduler(
                     applicationScope = scope,
-                    mainDispatcher = IMMEDIATE,
+                    mainDispatcher = kosmos.testDispatcher,
                     repository = repository,
                 ),
             uiEventLogger = uiEventLogger,
@@ -118,7 +122,7 @@
 
     @Test
     fun onDeviceBootCompleted_allowedToAdd_createGuest() =
-        runBlocking(IMMEDIATE) {
+        kosmos.runTest {
             setAllowedToAdd()
 
             underTest.onDeviceBootCompleted()
@@ -129,7 +133,7 @@
 
     @Test
     fun onDeviceBootCompleted_awaitProvisioning_andCreateGuest() =
-        runBlocking(IMMEDIATE) {
+        kosmos.runTest {
             setAllowedToAdd(isAllowed = false)
             underTest.onDeviceBootCompleted()
             val captor =
@@ -145,7 +149,7 @@
 
     @Test
     fun createAndSwitchTo() =
-        runBlocking(IMMEDIATE) {
+        kosmos.runTest {
             underTest.createAndSwitchTo(
                 showDialog = showDialog,
                 dismissDialog = dismissDialog,
@@ -160,7 +164,7 @@
 
     @Test
     fun createAndSwitchTo_failsToCreate_doesNotSwitchTo() =
-        runBlocking(IMMEDIATE) {
+        kosmos.runTest {
             whenever(manager.createGuest(any())).thenReturn(null)
 
             underTest.createAndSwitchTo(
@@ -177,7 +181,7 @@
 
     @Test
     fun exit_returnsToTargetUser() =
-        runBlocking(IMMEDIATE) {
+        kosmos.runTest {
             repository.setSelectedUserInfo(GUEST_USER_INFO)
 
             val targetUserId = NON_GUEST_USER_INFO.id
@@ -197,7 +201,7 @@
 
     @Test
     fun exit_returnsToLastNonGuest() =
-        runBlocking(IMMEDIATE) {
+        kosmos.runTest {
             val expectedUserId = NON_GUEST_USER_INFO.id
             whenever(manager.getUserInfo(expectedUserId)).thenReturn(NON_GUEST_USER_INFO)
             repository.lastSelectedNonGuestUserId = expectedUserId
@@ -219,7 +223,7 @@
 
     @Test
     fun exit_lastNonGuestWasRemoved_returnsToMainUser() =
-        runBlocking(IMMEDIATE) {
+        kosmos.runTest {
             val removedUserId = 310
             val mainUserId = 10
             repository.lastSelectedNonGuestUserId = removedUserId
@@ -242,7 +246,7 @@
 
     @Test
     fun exit_guestWasEphemeral_itIsRemoved() =
-        runBlocking(IMMEDIATE) {
+        kosmos.runTest {
             whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
             repository.setUserInfos(listOf(NON_GUEST_USER_INFO, EPHEMERAL_GUEST_USER_INFO))
             repository.setSelectedUserInfo(EPHEMERAL_GUEST_USER_INFO)
@@ -265,7 +269,7 @@
 
     @Test
     fun exit_forceRemoveGuest_itIsRemoved() =
-        runBlocking(IMMEDIATE) {
+        kosmos.runTest {
             whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
             repository.setSelectedUserInfo(GUEST_USER_INFO)
             val targetUserId = NON_GUEST_USER_INFO.id
@@ -287,7 +291,7 @@
 
     @Test
     fun exit_selectedDifferentFromGuestUser_doNothing() =
-        runBlocking(IMMEDIATE) {
+        kosmos.runTest {
             repository.setSelectedUserInfo(NON_GUEST_USER_INFO)
 
             underTest.exit(
@@ -304,7 +308,7 @@
 
     @Test
     fun exit_selectedIsActuallyNotAguestUser_doNothing() =
-        runBlocking(IMMEDIATE) {
+        kosmos.runTest {
             repository.setSelectedUserInfo(NON_GUEST_USER_INFO)
 
             underTest.exit(
@@ -321,7 +325,7 @@
 
     @Test
     fun remove_returnsToTargetUser() =
-        runBlocking(IMMEDIATE) {
+        kosmos.runTest {
             whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
             repository.setSelectedUserInfo(GUEST_USER_INFO)
 
@@ -342,7 +346,7 @@
 
     @Test
     fun remove_selectedDifferentFromGuestUser_doNothing() =
-        runBlocking(IMMEDIATE) {
+        kosmos.runTest {
             whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
             repository.setSelectedUserInfo(NON_GUEST_USER_INFO)
 
@@ -359,7 +363,7 @@
 
     @Test
     fun remove_selectedIsActuallyNotAguestUser_doNothing() =
-        runBlocking(IMMEDIATE) {
+        kosmos.runTest {
             whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
             repository.setSelectedUserInfo(NON_GUEST_USER_INFO)
 
@@ -395,11 +399,7 @@
     companion object {
         private val IMMEDIATE = Dispatchers.Main.immediate
         private val NON_GUEST_USER_INFO =
-            UserInfo(
-                /* id= */ 818,
-                /* name= */ "non_guest",
-                /* flags= */ UserInfo.FLAG_FULL,
-            )
+            UserInfo(/* id= */ 818, /* name= */ "non_guest", /* flags= */ UserInfo.FLAG_FULL)
         private val GUEST_USER_INFO =
             UserInfo(
                 /* id= */ 669,
@@ -416,10 +416,6 @@
                 /* flags= */ UserInfo.FLAG_EPHEMERAL or UserInfo.FLAG_FULL,
                 UserManager.USER_TYPE_FULL_GUEST,
             )
-        private val ALL_USERS =
-            listOf(
-                NON_GUEST_USER_INFO,
-                GUEST_USER_INFO,
-            )
+        private val ALL_USERS = listOf(NON_GUEST_USER_INFO, GUEST_USER_INFO)
     }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogEventLoggerTest.kt b/packages/SystemUI/multivalentTests/utils/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogEventLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogEventLoggerTest.kt
rename to packages/SystemUI/multivalentTests/utils/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogEventLoggerTest.kt
diff --git a/packages/SystemUI/plugin/Android.bp b/packages/SystemUI/plugin/Android.bp
index 6212e2b..2cd3346 100644
--- a/packages/SystemUI/plugin/Android.bp
+++ b/packages/SystemUI/plugin/Android.bp
@@ -55,6 +55,8 @@
         "SystemUICommon",
         "SystemUILogLib",
         "androidx.annotation_annotation",
+        "androidx.compose.ui_ui",
+        "androidx.compose.runtime_runtime",
     ],
 }
 
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/AuthContextPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/AuthContextPlugin.kt
new file mode 100644
index 0000000..773c2a2
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/AuthContextPlugin.kt
@@ -0,0 +1,85 @@
+/*
+ * 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.plugins
+
+import android.os.IBinder
+import android.view.View
+import com.android.systemui.plugins.annotations.ProvidesInterface
+
+/**
+ * Plugin for experimental "Contextual Auth" features.
+ *
+ * These plugins will get raw access to low-level events about the user's environment, such as
+ * moving in/out of trusted locations, connection status of trusted devices, auth attempts, etc.
+ * They will also receive callbacks related to system events & transitions to enable prototypes on
+ * sensitive surfaces like lock screen and BiometricPrompt.
+ *
+ * Note to rebuild the plugin jar run: m PluginDummyLib
+ */
+@ProvidesInterface(action = AuthContextPlugin.ACTION, version = AuthContextPlugin.VERSION)
+interface AuthContextPlugin : Plugin {
+
+    /**
+     * Called in the background when the plugin is enabled.
+     *
+     * This is a good time to ask your friendly [saucier] to cook up something special. The
+     * [Plugin.onCreate] can also be used for initialization.
+     */
+    fun activated(saucier: Saucier)
+
+    /**
+     * Called when a [SensitiveSurface] is first shown.
+     *
+     * This may be called repeatedly if the state of the surface changes after it is shown. For
+     * example, [SensitiveSurface.BiometricPrompt.isCredential] will change if the user falls back
+     * to a credential-based auth method.
+     */
+    fun onShowingSensitiveSurface(surface: SensitiveSurface)
+
+    /**
+     * Called when a [SensitiveSurface] sensitive surface is hidden.
+     *
+     * This method may still be called without [onShowingSensitiveSurface] in cases of rapid
+     * dismissal and plugins implementations should typically be idempotent.
+     */
+    fun onHidingSensitiveSurface(surface: SensitiveSurface)
+
+    companion object {
+        /** Plugin action. */
+        const val ACTION = "com.android.systemui.action.PLUGIN_AUTH_CONTEXT"
+        /** Plugin version. */
+        const val VERSION = 1
+    }
+
+    /** Information about a sensitive surface in the framework, which the Plugin may augment. */
+    sealed interface SensitiveSurface {
+
+        /** Information about the BiometricPrompt that is being shown to the user. */
+        data class BiometricPrompt(val view: View? = null, val isCredential: Boolean = false) :
+            SensitiveSurface
+
+        /** Information about bouncer. */
+        data class LockscreenBouncer(val view: View? = null) : SensitiveSurface
+    }
+
+    /** Ask for the special. */
+    interface Saucier {
+
+        /** What [flavor] would you like? */
+        fun getSauce(flavor: String): IBinder?
+    }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockAnimations.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockAnimations.kt
new file mode 100644
index 0000000..2df14a8
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockAnimations.kt
@@ -0,0 +1,61 @@
+/*
+ * 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.plugins.clocks
+
+import android.view.View
+import com.android.systemui.plugins.annotations.ProtectedInterface
+
+/** Methods which trigger various clock animations */
+@ProtectedInterface
+interface ClockAnimations {
+    /** Runs an enter animation (if any) */
+    fun enter()
+
+    /** Sets how far into AOD the device currently is. */
+    fun doze(fraction: Float)
+
+    /** Sets how far into the folding animation the device is. */
+    fun fold(fraction: Float)
+
+    /** Runs the battery animation (if any). */
+    fun charge()
+
+    /**
+     * Runs when the clock's position changed during the move animation.
+     *
+     * @param fromLeft the [View.getLeft] position of the clock, before it started moving.
+     * @param direction the direction in which it is moving. A positive number means right, and
+     *   negative means left.
+     * @param fraction fraction of the clock movement. 0 means it is at the beginning, and 1 means
+     *   it finished moving.
+     * @deprecated use {@link #onPositionUpdated(float, float)} instead.
+     */
+    fun onPositionUpdated(fromLeft: Int, direction: Int, fraction: Float)
+
+    /**
+     * Runs when the clock's position changed during the move animation.
+     *
+     * @param distance is the total distance in pixels to offset the glyphs when animation
+     *   completes. Negative distance means we are animating the position towards the center.
+     * @param fraction fraction of the clock movement. 0 means it is at the beginning, and 1 means
+     *   it finished moving.
+     */
+    fun onPositionUpdated(distance: Float, fraction: Float)
+
+    /**
+     * Runs when swiping clock picker, swipingFraction: 1.0 -> clock is scaled up in the preview,
+     * 0.0 -> clock is scaled down in the shade; previewRatio is previewSize / screenSize
+     */
+    fun onPickerCarouselSwiping(swipingFraction: Float)
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockConfig.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockConfig.kt
new file mode 100644
index 0000000..d84d890
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockConfig.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.plugins.clocks
+
+/**
+ * Exposes the rendering capabilities of this clock to SystemUI so that it can be hosted and render
+ * correctly in SystemUI's process. Ideally all clocks could be rendered identically, but in
+ * practice we different clocks require different behavior from SystemUI.
+ */
+data class ClockConfig(
+    val id: ClockId,
+
+    /** Localized name of the clock */
+    val name: String,
+
+    /** Localized accessibility description for the clock */
+    val description: String,
+
+    /** Transition to AOD should move smartspace like large clock instead of small clock */
+    val useAlternateSmartspaceAODTransition: Boolean = false,
+
+    /** Deprecated version of isReactiveToTone; moved to ClockPickerConfig */
+    @Deprecated("TODO(b/352049256): Remove in favor of ClockPickerConfig.isReactiveToTone")
+    val isReactiveToTone: Boolean = true,
+
+    /** True if the clock is large frame clock, which will use weather in compose. */
+    val useCustomClockScene: Boolean = false,
+)
+
+/** Render configuration options for a specific clock face. */
+data class ClockFaceConfig(
+    /** Expected interval between calls to onTimeTick. Can always reduce to PER_MINUTE in AOD. */
+    val tickRate: ClockTickRate = ClockTickRate.PER_MINUTE,
+
+    /** Call to check whether the clock consumes weather data */
+    val hasCustomWeatherDataDisplay: Boolean = false,
+
+    /**
+     * Whether this clock has a custom position update animation. If true, the keyguard will call
+     * `onPositionUpdated` to notify the clock of a position update animation. If false, a default
+     * animation will be used (e.g. a simple translation).
+     */
+    val hasCustomPositionUpdatedAnimation: Boolean = false,
+
+    /** True if the clock is large frame clock, which will use weatherBlueprint in compose. */
+    val useCustomClockScene: Boolean = false,
+)
+
+/** Tick rates for clocks */
+enum class ClockTickRate(val value: Int) {
+    PER_MINUTE(2), // Update the clock once per minute.
+    PER_SECOND(1), // Update the clock once per second.
+    PER_FRAME(0), // Update the clock every second.
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt
new file mode 100644
index 0000000..32fec32
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.plugins.clocks
+
+import com.android.systemui.plugins.annotations.ProtectedInterface
+import com.android.systemui.plugins.annotations.SimpleProperty
+import java.io.PrintWriter
+
+/** Interface for controlling an active clock */
+@ProtectedInterface
+interface ClockController {
+    @get:SimpleProperty
+    /** A small version of the clock, appropriate for smaller viewports */
+    val smallClock: ClockFaceController
+
+    @get:SimpleProperty
+    /** A large version of the clock, appropriate when a bigger viewport is available */
+    val largeClock: ClockFaceController
+
+    @get:SimpleProperty
+    /** Determines the way the hosting app should behave when rendering either clock face */
+    val config: ClockConfig
+
+    @get:SimpleProperty
+    /** Events that clocks may need to respond to */
+    val events: ClockEvents
+
+    /** Initializes various rendering parameters. If never called, provides reasonable defaults. */
+    fun initialize(isDarkTheme: Boolean, dozeFraction: Float, foldFraction: Float)
+
+    /** Optional method for dumping debug information */
+    fun dump(pw: PrintWriter)
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockEvents.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockEvents.kt
new file mode 100644
index 0000000..235475f
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockEvents.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.plugins.clocks
+
+import com.android.systemui.plugins.annotations.ProtectedInterface
+import com.android.systemui.plugins.annotations.ProtectedReturn
+import java.util.Locale
+import java.util.TimeZone
+
+/** Events that should call when various rendering parameters change */
+@ProtectedInterface
+interface ClockEvents {
+    @get:ProtectedReturn("return false;")
+    /** Set to enable or disable swipe interaction */
+    var isReactiveTouchInteractionEnabled: Boolean // TODO(b/364664388): Remove/Rename
+
+    /** Call whenever timezone changes */
+    fun onTimeZoneChanged(timeZone: TimeZone)
+
+    /** Call whenever the text time format changes (12hr vs 24hr) */
+    fun onTimeFormatChanged(is24Hr: Boolean)
+
+    /** Call whenever the locale changes */
+    fun onLocaleChanged(locale: Locale)
+
+    /** Call whenever the weather data should update */
+    fun onWeatherDataChanged(data: WeatherData)
+
+    /** Call with alarm information */
+    fun onAlarmDataChanged(data: AlarmData)
+
+    /** Call with zen/dnd information */
+    fun onZenDataChanged(data: ZenData)
+
+    /** Update reactive axes for this clock */
+    fun onFontAxesChanged(axes: List<ClockFontAxisSetting>)
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceController.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceController.kt
new file mode 100644
index 0000000..8a023f1
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceController.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.plugins.clocks
+
+import android.view.View
+import com.android.systemui.plugins.annotations.ProtectedInterface
+import com.android.systemui.plugins.annotations.SimpleProperty
+
+/** Interface for a specific clock face version rendered by the clock */
+@ProtectedInterface
+interface ClockFaceController {
+    @get:SimpleProperty
+    @Deprecated("Prefer use of layout")
+    /** View that renders the clock face */
+    val view: View
+
+    @get:SimpleProperty
+    /** Layout specification for this clock */
+    val layout: ClockFaceLayout
+
+    @get:SimpleProperty
+    /** Determines the way the hosting app should behave when rendering this clock face */
+    val config: ClockFaceConfig
+
+    @get:SimpleProperty
+    /** Current theme information the clock is using */
+    val theme: ThemeConfig
+
+    @get:SimpleProperty
+    /** Events specific to this clock face */
+    val events: ClockFaceEvents
+
+    @get:SimpleProperty
+    /** Triggers for various animations */
+    val animations: ClockAnimations
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceEvents.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceEvents.kt
new file mode 100644
index 0000000..029e546
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceEvents.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.plugins.clocks
+
+import android.graphics.Rect
+import com.android.systemui.plugins.annotations.ProtectedInterface
+
+/** Events that have specific data about the related face */
+@ProtectedInterface
+interface ClockFaceEvents {
+    /** Call every tick to update the rendered time */
+    fun onTimeTick()
+
+    /**
+     * Call whenever the theme or seedColor is updated
+     *
+     * Theme can be specific to the clock face.
+     * - isDarkTheme -> clock should be light
+     * - !isDarkTheme -> clock should be dark
+     */
+    fun onThemeChanged(theme: ThemeConfig)
+
+    /**
+     * Call whenever font settings change. Pass in a target font size in pixels. The specific clock
+     * design is allowed to ignore this target size on a case-by-case basis.
+     */
+    fun onFontSettingChanged(fontSizePx: Float)
+
+    /**
+     * Target region information for the clock face. For small clock, this will match the bounds of
+     * the parent view mostly, but have a target height based on the height of the default clock.
+     * For large clocks, the parent view is the entire device size, but most clocks will want to
+     * render within the centered targetRect to avoid obstructing other elements. The specified
+     * targetRegion is relative to the parent view.
+     */
+    fun onTargetRegionChanged(targetRegion: Rect?)
+
+    /** Called to notify the clock about its display. */
+    fun onSecondaryDisplayChanged(onSecondaryDisplay: Boolean)
+}
+
+/** Contains Theming information for the clock face */
+data class ThemeConfig(
+    /** True if the clock should use dark theme (light text on dark background) */
+    val isDarkTheme: Boolean,
+
+    /**
+     * A clock specific seed color to use when theming, if any was specified by the user. A null
+     * value denotes that we should use the seed color for the current system theme.
+     */
+    val seedColor: Int?,
+)
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceLayout.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceLayout.kt
new file mode 100644
index 0000000..fb5ef02
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceLayout.kt
@@ -0,0 +1,174 @@
+/*
+ * 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.plugins.clocks
+
+import android.content.Context
+import android.util.DisplayMetrics
+import android.view.View
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
+import androidx.constraintlayout.widget.ConstraintSet.END
+import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
+import androidx.constraintlayout.widget.ConstraintSet.START
+import androidx.constraintlayout.widget.ConstraintSet.TOP
+import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT
+import com.android.internal.policy.SystemBarUtils
+import com.android.systemui.plugins.annotations.GeneratedImport
+import com.android.systemui.plugins.annotations.ProtectedInterface
+import com.android.systemui.plugins.annotations.ProtectedReturn
+
+/** Specifies layout information for the clock face */
+@ProtectedInterface
+@GeneratedImport("java.util.ArrayList")
+@GeneratedImport("android.view.View")
+interface ClockFaceLayout {
+    @get:ProtectedReturn("return new ArrayList<View>();")
+    /** All clock views to add to the root constraint layout before applying constraints. */
+    val views: List<View>
+
+    @ProtectedReturn("return constraints;")
+    /** Custom constraints to apply to Lockscreen ConstraintLayout. */
+    fun applyConstraints(constraints: ConstraintSet): ConstraintSet
+
+    @ProtectedReturn("return constraints;")
+    /** Custom constraints to apply to preview ConstraintLayout. */
+    fun applyPreviewConstraints(
+        clockPreviewConfig: ClockPreviewConfig,
+        constraints: ConstraintSet,
+    ): ConstraintSet
+
+    /** Apply specified AOD BurnIn parameters to this layout */
+    fun applyAodBurnIn(aodBurnInModel: AodClockBurnInModel)
+}
+
+/** Data class to contain AOD BurnIn information for correct aod rendering */
+data class AodClockBurnInModel(
+    /** Scale that the clock should render at to mitigate burnin */
+    val scale: Float,
+
+    /** X-Translation for the clock to mitigate burnin */
+    val translationX: Float,
+
+    /** Y-Translation for the clock to mitigate burnin */
+    val translationY: Float,
+)
+
+/** A ClockFaceLayout that applies the default lockscreen layout to a single view */
+class DefaultClockFaceLayout(val view: View) : ClockFaceLayout {
+    override val views = listOf(view)
+
+    override fun applyConstraints(constraints: ConstraintSet): ConstraintSet {
+        if (views.size != 1) {
+            throw IllegalArgumentException(
+                "Should have only one container view when using DefaultClockFaceLayout"
+            )
+        }
+        return constraints
+    }
+
+    override fun applyPreviewConstraints(
+        clockPreviewConfig: ClockPreviewConfig,
+        constraints: ConstraintSet,
+    ): ConstraintSet {
+        return applyDefaultPreviewConstraints(clockPreviewConfig, constraints)
+    }
+
+    override fun applyAodBurnIn(aodBurnInModel: AodClockBurnInModel) {
+        // Default clock doesn't need detailed control of view
+    }
+
+    companion object {
+        fun applyDefaultPreviewConstraints(
+            clockPreviewConfig: ClockPreviewConfig,
+            constraints: ConstraintSet,
+        ): ConstraintSet {
+            constraints.apply {
+                val context = clockPreviewConfig.previewContext
+                val lockscreenClockViewLargeId = getId(context, "lockscreen_clock_view_large")
+                constrainWidth(lockscreenClockViewLargeId, WRAP_CONTENT)
+                constrainHeight(lockscreenClockViewLargeId, WRAP_CONTENT)
+                constrainMaxHeight(lockscreenClockViewLargeId, 0)
+
+                val largeClockTopMargin =
+                    SystemBarUtils.getStatusBarHeight(context) +
+                        getDimen(context, "small_clock_padding_top") +
+                        getDimen(context, "keyguard_smartspace_top_offset") +
+                        getDimen(context, "date_weather_view_height") +
+                        getDimen(context, "enhanced_smartspace_height")
+                connect(lockscreenClockViewLargeId, TOP, PARENT_ID, TOP, largeClockTopMargin)
+                connect(lockscreenClockViewLargeId, START, PARENT_ID, START)
+                connect(lockscreenClockViewLargeId, END, PARENT_ID, END)
+
+                // In preview, we'll show UDFPS icon for UDFPS devices
+                // and nothing for non-UDFPS devices,
+                // and we're not planning to add this vide in clockHostView
+                // so we only need position of device entry icon to constrain clock
+                // Copied calculation codes from applyConstraints in DefaultDeviceEntrySection
+                val bottomPaddingPx = getDimen(context, "lock_icon_margin_bottom")
+                val defaultDensity =
+                    DisplayMetrics.DENSITY_DEVICE_STABLE.toFloat() /
+                        DisplayMetrics.DENSITY_DEFAULT.toFloat()
+                val lockIconRadiusPx = (defaultDensity * 36).toInt()
+                val clockBottomMargin = bottomPaddingPx + 2 * lockIconRadiusPx
+
+                connect(lockscreenClockViewLargeId, BOTTOM, PARENT_ID, BOTTOM, clockBottomMargin)
+                val smallClockViewId = getId(context, "lockscreen_clock_view")
+                constrainWidth(smallClockViewId, WRAP_CONTENT)
+                constrainHeight(smallClockViewId, getDimen(context, "small_clock_height"))
+                connect(
+                    smallClockViewId,
+                    START,
+                    PARENT_ID,
+                    START,
+                    getDimen(context, "clock_padding_start") +
+                        getDimen(context, "status_view_margin_horizontal"),
+                )
+                val smallClockTopMargin =
+                    getSmallClockTopPadding(
+                        clockPreviewConfig = clockPreviewConfig,
+                        SystemBarUtils.getStatusBarHeight(context),
+                    )
+                connect(smallClockViewId, TOP, PARENT_ID, TOP, smallClockTopMargin)
+            }
+            return constraints
+        }
+
+        fun getId(context: Context, name: String): Int {
+            val packageName = context.packageName
+            val res = context.packageManager.getResourcesForApplication(packageName)
+            val id = res.getIdentifier(name, "id", packageName)
+            return id
+        }
+
+        fun getDimen(context: Context, name: String): Int {
+            val packageName = context.packageName
+            val res = context.resources
+            val id = res.getIdentifier(name, "dimen", packageName)
+            return if (id == 0) 0 else res.getDimensionPixelSize(id)
+        }
+
+        fun getSmallClockTopPadding(
+            clockPreviewConfig: ClockPreviewConfig,
+            statusBarHeight: Int,
+        ): Int {
+            return if (clockPreviewConfig.isShadeLayoutWide) {
+                getDimen(clockPreviewConfig.previewContext, "keyguard_split_shade_top_margin") -
+                    if (clockPreviewConfig.isSceneContainerFlagEnabled) statusBarHeight else 0
+            } else {
+                getDimen(clockPreviewConfig.previewContext, "keyguard_clock_top_margin") +
+                    if (!clockPreviewConfig.isSceneContainerFlagEnabled) statusBarHeight else 0
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockMessageBuffers.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockMessageBuffers.kt
new file mode 100644
index 0000000..bec589a
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockMessageBuffers.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.plugins.clocks
+
+import com.android.systemui.log.core.MessageBuffer
+
+/** MessageBuffers for clocks that want to log information to SystemUI dumps */
+data class ClockMessageBuffers(
+    /** Message buffer for general infrastructure */
+    val infraMessageBuffer: MessageBuffer,
+
+    /** Message buffer for small clock rendering */
+    val smallClockMessageBuffer: MessageBuffer,
+
+    /** Message buffer for large clock rendering */
+    val largeClockMessageBuffer: MessageBuffer,
+) {
+    constructor(buffer: MessageBuffer) : this(buffer, buffer, buffer) {}
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockPickerConfig.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockPickerConfig.kt
new file mode 100644
index 0000000..1bc9367
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockPickerConfig.kt
@@ -0,0 +1,87 @@
+/*
+ * 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.plugins.clocks
+
+import android.graphics.drawable.Drawable
+
+data class ClockPickerConfig
+@JvmOverloads
+constructor(
+    val id: String,
+
+    /** Localized name of the clock */
+    val name: String,
+
+    /** Localized accessibility description for the clock */
+    val description: String,
+
+    /* Static & lightweight thumbnail version of the clock */
+    val thumbnail: Drawable,
+
+    /** True if the clock will react to tone changes in the seed color */
+    val isReactiveToTone: Boolean = true,
+
+    /** Font axes that can be modified on this clock */
+    val axes: List<ClockFontAxis> = listOf(),
+)
+
+/** Represents an Axis that can be modified */
+data class ClockFontAxis(
+    /** Axis key, not user renderable */
+    val key: String,
+
+    /** Intended mode of user interaction */
+    val type: AxisType,
+
+    /** Maximum value the axis supports */
+    val maxValue: Float,
+
+    /** Minimum value the axis supports */
+    val minValue: Float,
+
+    /** Current value the axis is set to */
+    val currentValue: Float,
+
+    /** User-renderable name of the axis */
+    val name: String,
+
+    /** Description of the axis */
+    val description: String,
+) {
+    fun toSetting() = ClockFontAxisSetting(key, currentValue)
+
+    companion object {
+        fun merge(
+            fontAxes: List<ClockFontAxis>,
+            axisSettings: List<ClockFontAxisSetting>,
+        ): List<ClockFontAxis> {
+            val result = mutableListOf<ClockFontAxis>()
+            for (axis in fontAxes) {
+                val setting = axisSettings.firstOrNull { axis.key == it.key }
+                val output = setting?.let { axis.copy(currentValue = it.value) } ?: axis
+                result.add(output)
+            }
+            return result
+        }
+    }
+}
+
+/** Axis user interaction modes */
+enum class AxisType {
+    /** Continuous range between minValue & maxValue. */
+    Float,
+
+    /** Only minValue & maxValue are valid. No intermediate values between them are allowed. */
+    Boolean,
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockPreviewConfig.kt
similarity index 71%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockPreviewConfig.kt
index 7d3d8b9..544b705 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockPreviewConfig.kt
@@ -13,10 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
-}
+package com.android.systemui.plugins.clocks
+
+import android.content.Context
+
+data class ClockPreviewConfig(
+    val previewContext: Context,
+    val isShadeLayoutWide: Boolean,
+    val isSceneContainerFlagEnabled: Boolean = false,
+)
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
index fb9e96c..7426f06 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
@@ -13,35 +13,11 @@
  */
 package com.android.systemui.plugins.clocks
 
-import android.content.Context
-import android.graphics.Rect
-import android.graphics.drawable.Drawable
-import android.util.DisplayMetrics
-import android.view.View
-import androidx.constraintlayout.widget.ConstraintSet
-import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
-import androidx.constraintlayout.widget.ConstraintSet.END
-import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
-import androidx.constraintlayout.widget.ConstraintSet.START
-import androidx.constraintlayout.widget.ConstraintSet.TOP
-import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT
-import com.android.internal.annotations.Keep
-import com.android.internal.policy.SystemBarUtils
-import com.android.systemui.log.core.MessageBuffer
 import com.android.systemui.plugins.Plugin
 import com.android.systemui.plugins.annotations.GeneratedImport
 import com.android.systemui.plugins.annotations.ProtectedInterface
 import com.android.systemui.plugins.annotations.ProtectedReturn
 import com.android.systemui.plugins.annotations.ProvidesInterface
-import com.android.systemui.plugins.annotations.SimpleProperty
-import java.io.PrintWriter
-import java.util.Locale
-import java.util.TimeZone
-import org.json.JSONArray
-import org.json.JSONObject
-
-/** Identifies a clock design */
-typealias ClockId = String
 
 /** A Plugin which exposes the ClockProvider interface */
 @ProtectedInterface
@@ -74,509 +50,8 @@
     fun getClockPickerConfig(settings: ClockSettings): ClockPickerConfig
 }
 
-/** Interface for controlling an active clock */
-@ProtectedInterface
-interface ClockController {
-    @get:SimpleProperty
-    /** A small version of the clock, appropriate for smaller viewports */
-    val smallClock: ClockFaceController
-
-    @get:SimpleProperty
-    /** A large version of the clock, appropriate when a bigger viewport is available */
-    val largeClock: ClockFaceController
-
-    @get:SimpleProperty
-    /** Determines the way the hosting app should behave when rendering either clock face */
-    val config: ClockConfig
-
-    @get:SimpleProperty
-    /** Events that clocks may need to respond to */
-    val events: ClockEvents
-
-    /** Initializes various rendering parameters. If never called, provides reasonable defaults. */
-    fun initialize(isDarkTheme: Boolean, dozeFraction: Float, foldFraction: Float)
-
-    /** Optional method for dumping debug information */
-    fun dump(pw: PrintWriter)
-}
-
-/** Interface for a specific clock face version rendered by the clock */
-@ProtectedInterface
-interface ClockFaceController {
-    @get:SimpleProperty
-    @Deprecated("Prefer use of layout")
-    /** View that renders the clock face */
-    val view: View
-
-    @get:SimpleProperty
-    /** Layout specification for this clock */
-    val layout: ClockFaceLayout
-
-    @get:SimpleProperty
-    /** Determines the way the hosting app should behave when rendering this clock face */
-    val config: ClockFaceConfig
-
-    @get:SimpleProperty
-    /** Current theme information the clock is using */
-    val theme: ThemeConfig
-
-    @get:SimpleProperty
-    /** Events specific to this clock face */
-    val events: ClockFaceEvents
-
-    @get:SimpleProperty
-    /** Triggers for various animations */
-    val animations: ClockAnimations
-}
-
-/** For clocks that want to report debug information */
-data class ClockMessageBuffers(
-    /** Message buffer for general infra */
-    val infraMessageBuffer: MessageBuffer,
-
-    /** Message buffer for small clock renering */
-    val smallClockMessageBuffer: MessageBuffer,
-
-    /** Message buffer for large clock rendering */
-    val largeClockMessageBuffer: MessageBuffer,
-) {
-    constructor(buffer: MessageBuffer) : this(buffer, buffer, buffer) {}
-}
-
-data class AodClockBurnInModel(val scale: Float, val translationX: Float, val translationY: Float)
-
-/** Specifies layout information for the clock face */
-@ProtectedInterface
-@GeneratedImport("java.util.ArrayList")
-@GeneratedImport("android.view.View")
-interface ClockFaceLayout {
-    @get:ProtectedReturn("return new ArrayList<View>();")
-    /** All clock views to add to the root constraint layout before applying constraints. */
-    val views: List<View>
-
-    @ProtectedReturn("return constraints;")
-    /** Custom constraints to apply to Lockscreen ConstraintLayout. */
-    fun applyConstraints(constraints: ConstraintSet): ConstraintSet
-
-    @ProtectedReturn("return constraints;")
-    /** Custom constraints to apply to preview ConstraintLayout. */
-    fun applyPreviewConstraints(context: Context, constraints: ConstraintSet): ConstraintSet
-
-    fun applyAodBurnIn(aodBurnInModel: AodClockBurnInModel)
-}
-
-/** A ClockFaceLayout that applies the default lockscreen layout to a single view */
-class DefaultClockFaceLayout(val view: View) : ClockFaceLayout {
-    // both small and large clock should have a container (RelativeLayout in
-    // SimpleClockFaceController)
-    override val views = listOf(view)
-
-    override fun applyConstraints(constraints: ConstraintSet): ConstraintSet {
-        if (views.size != 1) {
-            throw IllegalArgumentException(
-                "Should have only one container view when using DefaultClockFaceLayout"
-            )
-        }
-        return constraints
-    }
-
-    override fun applyPreviewConstraints(
-        context: Context,
-        constraints: ConstraintSet,
-    ): ConstraintSet {
-        return applyDefaultPreviewConstraints(context, constraints)
-    }
-
-    override fun applyAodBurnIn(aodBurnInModel: AodClockBurnInModel) {
-        // Default clock doesn't need detailed control of view
-    }
-
-    companion object {
-        fun applyDefaultPreviewConstraints(
-            context: Context,
-            constraints: ConstraintSet,
-        ): ConstraintSet {
-            constraints.apply {
-                val lockscreenClockViewLargeId = getId(context, "lockscreen_clock_view_large")
-                constrainWidth(lockscreenClockViewLargeId, WRAP_CONTENT)
-                constrainHeight(lockscreenClockViewLargeId, WRAP_CONTENT)
-                constrainMaxHeight(lockscreenClockViewLargeId, 0)
-
-                val largeClockTopMargin =
-                    SystemBarUtils.getStatusBarHeight(context) +
-                        getDimen(context, "small_clock_padding_top") +
-                        getDimen(context, "keyguard_smartspace_top_offset") +
-                        getDimen(context, "date_weather_view_height") +
-                        getDimen(context, "enhanced_smartspace_height")
-                connect(lockscreenClockViewLargeId, TOP, PARENT_ID, TOP, largeClockTopMargin)
-                connect(lockscreenClockViewLargeId, START, PARENT_ID, START)
-                connect(lockscreenClockViewLargeId, END, PARENT_ID, END)
-
-                // In preview, we'll show UDFPS icon for UDFPS devices
-                // and nothing for non-UDFPS devices,
-                // and we're not planning to add this vide in clockHostView
-                // so we only need position of device entry icon to constrain clock
-                // Copied calculation codes from applyConstraints in DefaultDeviceEntrySection
-                val bottomPaddingPx = getDimen(context, "lock_icon_margin_bottom")
-                val defaultDensity =
-                    DisplayMetrics.DENSITY_DEVICE_STABLE.toFloat() /
-                        DisplayMetrics.DENSITY_DEFAULT.toFloat()
-                val lockIconRadiusPx = (defaultDensity * 36).toInt()
-                val clockBottomMargin = bottomPaddingPx + 2 * lockIconRadiusPx
-
-                connect(lockscreenClockViewLargeId, BOTTOM, PARENT_ID, BOTTOM, clockBottomMargin)
-                val smallClockViewId = getId(context, "lockscreen_clock_view")
-                constrainWidth(smallClockViewId, WRAP_CONTENT)
-                constrainHeight(smallClockViewId, getDimen(context, "small_clock_height"))
-                connect(
-                    smallClockViewId,
-                    START,
-                    PARENT_ID,
-                    START,
-                    getDimen(context, "clock_padding_start") +
-                        getDimen(context, "status_view_margin_horizontal"),
-                )
-                val smallClockTopMargin =
-                    getDimen(context, "keyguard_clock_top_margin") +
-                        SystemBarUtils.getStatusBarHeight(context)
-                connect(smallClockViewId, TOP, PARENT_ID, TOP, smallClockTopMargin)
-            }
-            return constraints
-        }
-
-        fun getId(context: Context, name: String): Int {
-            val packageName = context.packageName
-            val res = context.packageManager.getResourcesForApplication(packageName)
-            val id = res.getIdentifier(name, "id", packageName)
-            return id
-        }
-
-        fun getDimen(context: Context, name: String): Int {
-            val packageName = context.packageName
-            val res = context.packageManager.getResourcesForApplication(packageName)
-            val id = res.getIdentifier(name, "dimen", packageName)
-            return if (id == 0) 0 else res.getDimensionPixelSize(id)
-        }
-    }
-}
-
-/** Events that should call when various rendering parameters change */
-@ProtectedInterface
-interface ClockEvents {
-    @get:ProtectedReturn("return false;")
-    /** Set to enable or disable swipe interaction */
-    var isReactiveTouchInteractionEnabled: Boolean // TODO(b/364664388): Remove/Rename
-
-    /** Call whenever timezone changes */
-    fun onTimeZoneChanged(timeZone: TimeZone)
-
-    /** Call whenever the text time format changes (12hr vs 24hr) */
-    fun onTimeFormatChanged(is24Hr: Boolean)
-
-    /** Call whenever the locale changes */
-    fun onLocaleChanged(locale: Locale)
-
-    /** Call whenever the weather data should update */
-    fun onWeatherDataChanged(data: WeatherData)
-
-    /** Call with alarm information */
-    fun onAlarmDataChanged(data: AlarmData)
-
-    /** Call with zen/dnd information */
-    fun onZenDataChanged(data: ZenData)
-
-    /** Update reactive axes for this clock */
-    fun onFontAxesChanged(axes: List<ClockFontAxisSetting>)
-}
-
-/** Axis setting value for a clock */
-data class ClockFontAxisSetting(
-    /** Axis key; matches ClockFontAxis.key */
-    val key: String,
-
-    /** Value to set this axis to */
-    val value: Float,
-) {
-    companion object {
-        private val KEY_AXIS_KEY = "key"
-        private val KEY_AXIS_VALUE = "value"
-
-        fun toJson(setting: ClockFontAxisSetting): JSONObject {
-            return JSONObject().apply {
-                put(KEY_AXIS_KEY, setting.key)
-                put(KEY_AXIS_VALUE, setting.value)
-            }
-        }
-
-        fun toJson(settings: List<ClockFontAxisSetting>): JSONArray {
-            return JSONArray().apply {
-                for (axis in settings) {
-                    put(toJson(axis))
-                }
-            }
-        }
-
-        fun fromJson(jsonObj: JSONObject): ClockFontAxisSetting {
-            return ClockFontAxisSetting(
-                key = jsonObj.getString(KEY_AXIS_KEY),
-                value = jsonObj.getDouble(KEY_AXIS_VALUE).toFloat(),
-            )
-        }
-
-        fun fromJson(jsonArray: JSONArray): List<ClockFontAxisSetting> {
-            val result = mutableListOf<ClockFontAxisSetting>()
-            for (i in 0..jsonArray.length() - 1) {
-                val obj = jsonArray.getJSONObject(i)
-                if (obj == null) continue
-                result.add(fromJson(obj))
-            }
-            return result
-        }
-
-        fun toFVar(settings: List<ClockFontAxisSetting>): String {
-            val sb = StringBuilder()
-            for (axis in settings) {
-                if (sb.length > 0) sb.append(", ")
-                sb.append("'${axis.key}' ${axis.value.toInt()}")
-            }
-            return sb.toString()
-        }
-    }
-}
-
-/** Methods which trigger various clock animations */
-@ProtectedInterface
-interface ClockAnimations {
-    /** Runs an enter animation (if any) */
-    fun enter()
-
-    /** Sets how far into AOD the device currently is. */
-    fun doze(fraction: Float)
-
-    /** Sets how far into the folding animation the device is. */
-    fun fold(fraction: Float)
-
-    /** Runs the battery animation (if any). */
-    fun charge()
-
-    /**
-     * Runs when the clock's position changed during the move animation.
-     *
-     * @param fromLeft the [View.getLeft] position of the clock, before it started moving.
-     * @param direction the direction in which it is moving. A positive number means right, and
-     *   negative means left.
-     * @param fraction fraction of the clock movement. 0 means it is at the beginning, and 1 means
-     *   it finished moving.
-     * @deprecated use {@link #onPositionUpdated(float, float)} instead.
-     */
-    fun onPositionUpdated(fromLeft: Int, direction: Int, fraction: Float)
-
-    /**
-     * Runs when the clock's position changed during the move animation.
-     *
-     * @param distance is the total distance in pixels to offset the glyphs when animation
-     *   completes. Negative distance means we are animating the position towards the center.
-     * @param fraction fraction of the clock movement. 0 means it is at the beginning, and 1 means
-     *   it finished moving.
-     */
-    fun onPositionUpdated(distance: Float, fraction: Float)
-
-    /**
-     * Runs when swiping clock picker, swipingFraction: 1.0 -> clock is scaled up in the preview,
-     * 0.0 -> clock is scaled down in the shade; previewRatio is previewSize / screenSize
-     */
-    fun onPickerCarouselSwiping(swipingFraction: Float)
-}
-
-/** Events that have specific data about the related face */
-@ProtectedInterface
-interface ClockFaceEvents {
-    /** Call every time tick */
-    fun onTimeTick()
-
-    /**
-     * Call whenever the theme or seedColor is updated
-     *
-     * Theme can be specific to the clock face.
-     * - isDarkTheme -> clock should be light
-     * - !isDarkTheme -> clock should be dark
-     */
-    fun onThemeChanged(theme: ThemeConfig)
-
-    /**
-     * Call whenever font settings change. Pass in a target font size in pixels. The specific clock
-     * design is allowed to ignore this target size on a case-by-case basis.
-     */
-    fun onFontSettingChanged(fontSizePx: Float)
-
-    /**
-     * Target region information for the clock face. For small clock, this will match the bounds of
-     * the parent view mostly, but have a target height based on the height of the default clock.
-     * For large clocks, the parent view is the entire device size, but most clocks will want to
-     * render within the centered targetRect to avoid obstructing other elements. The specified
-     * targetRegion is relative to the parent view.
-     */
-    fun onTargetRegionChanged(targetRegion: Rect?)
-
-    /** Called to notify the clock about its display. */
-    fun onSecondaryDisplayChanged(onSecondaryDisplay: Boolean)
-}
-
-data class ThemeConfig(val isDarkTheme: Boolean, val seedColor: Int?)
-
-/** Tick rates for clocks */
-enum class ClockTickRate(val value: Int) {
-    PER_MINUTE(2), // Update the clock once per minute.
-    PER_SECOND(1), // Update the clock once per second.
-    PER_FRAME(0), // Update the clock every second.
-}
+/** Identifies a clock design */
+typealias ClockId = String
 
 /** Some data about a clock design */
 data class ClockMetadata(val clockId: ClockId)
-
-data class ClockPickerConfig
-@JvmOverloads
-constructor(
-    val id: String,
-
-    /** Localized name of the clock */
-    val name: String,
-
-    /** Localized accessibility description for the clock */
-    val description: String,
-
-    /* Static & lightweight thumbnail version of the clock */
-    val thumbnail: Drawable,
-
-    /** True if the clock will react to tone changes in the seed color */
-    val isReactiveToTone: Boolean = true,
-
-    /** Font axes that can be modified on this clock */
-    val axes: List<ClockFontAxis> = listOf(),
-)
-
-/** Represents an Axis that can be modified */
-data class ClockFontAxis(
-    /** Axis key, not user renderable */
-    val key: String,
-
-    /** Intended mode of user interaction */
-    val type: AxisType,
-
-    /** Maximum value the axis supports */
-    val maxValue: Float,
-
-    /** Minimum value the axis supports */
-    val minValue: Float,
-
-    /** Current value the axis is set to */
-    val currentValue: Float,
-
-    /** User-renderable name of the axis */
-    val name: String,
-
-    /** Description of the axis */
-    val description: String,
-) {
-    fun toSetting() = ClockFontAxisSetting(key, currentValue)
-
-    companion object {
-        fun merge(
-            fontAxes: List<ClockFontAxis>,
-            axisSettings: List<ClockFontAxisSetting>,
-        ): List<ClockFontAxis> {
-            val result = mutableListOf<ClockFontAxis>()
-            for (axis in fontAxes) {
-                val setting = axisSettings.firstOrNull { axis.key == it.key }
-                val output = setting?.let { axis.copy(currentValue = it.value) } ?: axis
-                result.add(output)
-            }
-            return result
-        }
-    }
-}
-
-/** Axis user interaction modes */
-enum class AxisType {
-    /** Continuous range between minValue & maxValue. */
-    Float,
-
-    /** Only minValue & maxValue are valid. No intermediate values between them are allowed. */
-    Boolean,
-}
-
-/** Render configuration for the full clock. Modifies the way systemUI behaves with this clock. */
-data class ClockConfig(
-    val id: String,
-
-    /** Localized name of the clock */
-    val name: String,
-
-    /** Localized accessibility description for the clock */
-    val description: String,
-
-    /** Transition to AOD should move smartspace like large clock instead of small clock */
-    val useAlternateSmartspaceAODTransition: Boolean = false,
-
-    /** Deprecated version of isReactiveToTone; moved to ClockPickerConfig */
-    @Deprecated("TODO(b/352049256): Remove in favor of ClockPickerConfig.isReactiveToTone")
-    val isReactiveToTone: Boolean = true,
-
-    /** True if the clock is large frame clock, which will use weather in compose. */
-    val useCustomClockScene: Boolean = false,
-)
-
-/** Render configuration options for a clock face. Modifies the way SystemUI behaves. */
-data class ClockFaceConfig(
-    /** Expected interval between calls to onTimeTick. Can always reduce to PER_MINUTE in AOD. */
-    val tickRate: ClockTickRate = ClockTickRate.PER_MINUTE,
-
-    /** Call to check whether the clock consumes weather data */
-    val hasCustomWeatherDataDisplay: Boolean = false,
-
-    /**
-     * Whether this clock has a custom position update animation. If true, the keyguard will call
-     * `onPositionUpdated` to notify the clock of a position update animation. If false, a default
-     * animation will be used (e.g. a simple translation).
-     */
-    val hasCustomPositionUpdatedAnimation: Boolean = false,
-
-    /** True if the clock is large frame clock, which will use weatherBlueprint in compose. */
-    val useCustomClockScene: Boolean = false,
-)
-
-/** Structure for keeping clock-specific settings */
-@Keep
-data class ClockSettings(
-    val clockId: ClockId? = null,
-    val seedColor: Int? = null,
-    val axes: List<ClockFontAxisSetting> = listOf(),
-) {
-    // Exclude metadata from equality checks
-    var metadata: JSONObject = JSONObject()
-
-    companion object {
-        private val KEY_CLOCK_ID = "clockId"
-        private val KEY_SEED_COLOR = "seedColor"
-        private val KEY_METADATA = "metadata"
-        private val KEY_AXIS_LIST = "axes"
-
-        fun toJson(setting: ClockSettings): JSONObject {
-            return JSONObject().apply {
-                put(KEY_CLOCK_ID, setting.clockId)
-                put(KEY_SEED_COLOR, setting.seedColor)
-                put(KEY_METADATA, setting.metadata)
-                put(KEY_AXIS_LIST, ClockFontAxisSetting.toJson(setting.axes))
-            }
-        }
-
-        fun fromJson(json: JSONObject): ClockSettings {
-            val clockId = if (!json.isNull(KEY_CLOCK_ID)) json.getString(KEY_CLOCK_ID) else null
-            val seedColor = if (!json.isNull(KEY_SEED_COLOR)) json.getInt(KEY_SEED_COLOR) else null
-            val axisList = json.optJSONArray(KEY_AXIS_LIST)?.let(ClockFontAxisSetting::fromJson)
-            return ClockSettings(clockId, seedColor, axisList ?: listOf()).apply {
-                metadata = json.optJSONObject(KEY_METADATA) ?: JSONObject()
-            }
-        }
-    }
-}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockSettings.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockSettings.kt
new file mode 100644
index 0000000..6128c00
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockSettings.kt
@@ -0,0 +1,110 @@
+/*
+ * 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.plugins.clocks
+
+import com.android.internal.annotations.Keep
+import org.json.JSONArray
+import org.json.JSONObject
+
+@Keep
+/** Structure for keeping clock-specific settings */
+data class ClockSettings(
+    val clockId: ClockId? = null,
+    val seedColor: Int? = null,
+    val axes: List<ClockFontAxisSetting> = listOf(),
+) {
+    // Exclude metadata from equality checks
+    var metadata: JSONObject = JSONObject()
+
+    companion object {
+        private val KEY_CLOCK_ID = "clockId"
+        private val KEY_SEED_COLOR = "seedColor"
+        private val KEY_METADATA = "metadata"
+        private val KEY_AXIS_LIST = "axes"
+
+        fun toJson(setting: ClockSettings): JSONObject {
+            return JSONObject().apply {
+                put(KEY_CLOCK_ID, setting.clockId)
+                put(KEY_SEED_COLOR, setting.seedColor)
+                put(KEY_METADATA, setting.metadata)
+                put(KEY_AXIS_LIST, ClockFontAxisSetting.toJson(setting.axes))
+            }
+        }
+
+        fun fromJson(json: JSONObject): ClockSettings {
+            val clockId = if (!json.isNull(KEY_CLOCK_ID)) json.getString(KEY_CLOCK_ID) else null
+            val seedColor = if (!json.isNull(KEY_SEED_COLOR)) json.getInt(KEY_SEED_COLOR) else null
+            val axisList = json.optJSONArray(KEY_AXIS_LIST)?.let(ClockFontAxisSetting::fromJson)
+            return ClockSettings(clockId, seedColor, axisList ?: listOf()).apply {
+                metadata = json.optJSONObject(KEY_METADATA) ?: JSONObject()
+            }
+        }
+    }
+}
+
+@Keep
+/** Axis setting value for a clock */
+data class ClockFontAxisSetting(
+    /** Axis key; matches ClockFontAxis.key */
+    val key: String,
+
+    /** Value to set this axis to */
+    val value: Float,
+) {
+    companion object {
+        private val KEY_AXIS_KEY = "key"
+        private val KEY_AXIS_VALUE = "value"
+
+        fun toJson(setting: ClockFontAxisSetting): JSONObject {
+            return JSONObject().apply {
+                put(KEY_AXIS_KEY, setting.key)
+                put(KEY_AXIS_VALUE, setting.value)
+            }
+        }
+
+        fun toJson(settings: List<ClockFontAxisSetting>): JSONArray {
+            return JSONArray().apply {
+                for (axis in settings) {
+                    put(toJson(axis))
+                }
+            }
+        }
+
+        fun fromJson(jsonObj: JSONObject): ClockFontAxisSetting {
+            return ClockFontAxisSetting(
+                key = jsonObj.getString(KEY_AXIS_KEY),
+                value = jsonObj.getDouble(KEY_AXIS_VALUE).toFloat(),
+            )
+        }
+
+        fun fromJson(jsonArray: JSONArray): List<ClockFontAxisSetting> {
+            val result = mutableListOf<ClockFontAxisSetting>()
+            for (i in 0..jsonArray.length() - 1) {
+                val obj = jsonArray.getJSONObject(i)
+                if (obj == null) continue
+                result.add(fromJson(obj))
+            }
+            return result
+        }
+
+        fun toFVar(settings: List<ClockFontAxisSetting>): String {
+            val sb = StringBuilder()
+            for (axis in settings) {
+                if (sb.length > 0) sb.append(", ")
+                sb.append("'${axis.key}' ${axis.value.toInt()}")
+            }
+            return sb.toString()
+        }
+    }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index 73626b4..e3cbd66 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -120,6 +120,11 @@
      */
     boolean isListening();
 
+    /**
+     * Return this tile's {@link TileDetailsViewModel} to be used to render the TileDetailsView.
+     */
+    default TileDetailsViewModel getDetailsViewModel() { return null; }
+
     @ProvidesInterface(version = Callback.VERSION)
     interface Callback {
         static final int VERSION = 2;
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/TileDetailsViewModel.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/TileDetailsViewModel.kt
new file mode 100644
index 0000000..eab7d79
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/TileDetailsViewModel.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.plugins.qs
+
+import androidx.compose.runtime.Composable
+
+/**
+ * The base view model class for rendering the Tile's TileDetailsView.
+ */
+abstract class TileDetailsViewModel {
+
+    // The view content of this tile details view.
+    @Composable
+    abstract fun GetContentView()
+
+    // The callback when the settings button is clicked. Currently this is the same as the on tile
+    // long press callback
+    abstract fun clickOnSettingsButton()
+
+    abstract fun getTitle(): String
+
+    abstract fun getSubTitle(): String
+}
diff --git a/packages/SystemUI/res/drawable/volume_background_top_legacy.xml b/packages/SystemUI/res/drawable/volume_background_top_legacy.xml
index 3cd87fc..58ae150 100644
--- a/packages/SystemUI/res/drawable/volume_background_top_legacy.xml
+++ b/packages/SystemUI/res/drawable/volume_background_top_legacy.xml
@@ -16,7 +16,7 @@
   -->
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <item>
+    <item android:gravity="bottom|end">
         <shape>
             <size android:width="@dimen/volume_dialog_panel_width" />
             <solid android:color="?androidprv:attr/colorSurface" />
diff --git a/packages/SystemUI/res/layout/audio_sharing_dialog.xml b/packages/SystemUI/res/layout/audio_sharing_dialog.xml
index 7534e15..014b7f7 100644
--- a/packages/SystemUI/res/layout/audio_sharing_dialog.xml
+++ b/packages/SystemUI/res/layout/audio_sharing_dialog.xml
@@ -84,7 +84,7 @@
         android:id="@+id/share_audio_button"
         style="@style/SettingsLibActionButton"
         android:textColor="?androidprv:attr/textColorOnAccent"
-        android:background="@drawable/audio_sharing_rounded_bg_ripple"
+        android:background="@drawable/audio_sharing_rounded_bg_ripple_top"
         android:layout_marginBottom="4dp"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
@@ -101,7 +101,7 @@
         android:id="@+id/switch_active_button"
         style="@style/SettingsLibActionButton"
         android:textColor="?androidprv:attr/textColorOnAccent"
-        android:background="@drawable/audio_sharing_rounded_bg_ripple"
+        android:background="@drawable/audio_sharing_rounded_bg_ripple_bottom"
         android:layout_marginBottom="20dp"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/controls_management.xml b/packages/SystemUI/res/layout/controls_management.xml
index d8967d4..e90471e 100644
--- a/packages/SystemUI/res/layout/controls_management.xml
+++ b/packages/SystemUI/res/layout/controls_management.xml
@@ -22,7 +22,6 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="center_horizontal"
-    android:paddingTop="@dimen/controls_management_top_padding"
     android:paddingStart="@dimen/controls_management_side_padding"
     android:paddingEnd="@dimen/controls_management_side_padding" >
 
diff --git a/packages/SystemUI/res/layout/custom_trace_settings_dialog.xml b/packages/SystemUI/res/layout/custom_trace_settings_dialog.xml
index 9e84052..17c2f89 100644
--- a/packages/SystemUI/res/layout/custom_trace_settings_dialog.xml
+++ b/packages/SystemUI/res/layout/custom_trace_settings_dialog.xml
@@ -26,6 +26,8 @@
         android:layout_height="wrap_content"
         android:layout_gravity="center"
         android:layout_marginTop="@dimen/qqs_layout_margin_top"
+        android:minHeight="@dimen/min_clickable_item_size"
+        android:minWidth="@dimen/min_clickable_item_size"
         android:textAppearance="@style/TextAppearance.Dialog.Body.Message" />
 
     <TextView
@@ -34,6 +36,8 @@
         android:layout_height="wrap_content"
         android:layout_gravity="center"
         android:layout_marginTop="@dimen/qqs_layout_margin_top"
+        android:minHeight="@dimen/min_clickable_item_size"
+        android:minWidth="@dimen/min_clickable_item_size"
         android:textAppearance="@style/TextAppearance.Dialog.Body.Message" />
 
     <!-- Attach to Bugreport Switch -->
@@ -58,9 +62,9 @@
         <Switch
             android:id="@+id/attach_to_bugreport_switch"
             android:layout_width="wrap_content"
-            android:minHeight="@dimen/screenrecord_option_icon_size"
             android:layout_height="wrap_content"
             android:gravity="end"
+            style="@style/ScreenRecord.Switch"
             android:layout_gravity="fill_vertical"
             android:layout_weight="0" />
     </LinearLayout>
@@ -87,9 +91,9 @@
         <Switch
             android:id="@+id/winscope_switch"
             android:layout_width="wrap_content"
-            android:minHeight="@dimen/screenrecord_option_icon_size"
             android:layout_height="wrap_content"
             android:gravity="end"
+            style="@style/ScreenRecord.Switch"
             android:layout_gravity="fill_vertical"
             android:layout_weight="0" />
     </LinearLayout>
@@ -116,9 +120,9 @@
         <Switch
             android:id="@+id/trace_debuggable_apps_switch"
             android:layout_width="wrap_content"
-            android:minHeight="@dimen/screenrecord_option_icon_size"
             android:layout_height="wrap_content"
             android:gravity="end"
+            style="@style/ScreenRecord.Switch"
             android:layout_gravity="fill_vertical"
             android:layout_weight="0" />
     </LinearLayout>
@@ -145,9 +149,9 @@
         <Switch
             android:id="@+id/long_traces_switch"
             android:layout_width="wrap_content"
-            android:minHeight="@dimen/screenrecord_option_icon_size"
             android:layout_height="wrap_content"
             android:gravity="end"
+            style="@style/ScreenRecord.Switch"
             android:layout_gravity="fill_vertical"
             android:layout_weight="0" />
     </LinearLayout>
diff --git a/packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml b/packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml
index ff5d9d3..a338e4c 100644
--- a/packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml
+++ b/packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml
@@ -29,16 +29,18 @@
         android:layout_height="@dimen/notification_2025_single_line_face_pile_size"
         android:layout_marginEnd="8dp"
     >
-        <ImageView
+        <com.android.internal.widget.CachingIconView
             android:id="@*android:id/conversation_icon"
             android:layout_width="@dimen/notification_2025_single_line_avatar_size"
             android:layout_height="@dimen/notification_2025_single_line_avatar_size"
             android:layout_gravity="center_vertical|end"
+            android:background="@*android:drawable/notification_icon_circle"
+            android:clipToOutline="true"
         />
 
         <ViewStub
             android:id="@*android:id/conversation_face_pile"
-            android:layout="@*android:layout/conversation_face_pile_layout"
+            android:layout="@*android:layout/notification_2025_conversation_face_pile_layout"
             android:layout_width="@dimen/notification_2025_single_line_face_pile_size"
             android:layout_height="@dimen/notification_2025_single_line_face_pile_size"
             android:layout_gravity="center_vertical|end"
diff --git a/packages/SystemUI/res/layout/record_issue_dialog.xml b/packages/SystemUI/res/layout/record_issue_dialog.xml
index e30ae6e..b2a8c4c 100644
--- a/packages/SystemUI/res/layout/record_issue_dialog.xml
+++ b/packages/SystemUI/res/layout/record_issue_dialog.xml
@@ -38,6 +38,8 @@
         android:drawableEnd="@drawable/arrow_pointing_down"
         android:layout_marginTop="@dimen/qqs_layout_margin_top"
         android:focusable="false"
+        android:minHeight="@dimen/min_clickable_item_size"
+        android:minWidth="@dimen/min_clickable_item_size"
         android:clickable="true" />
 
     <!-- Screen Record Switch -->
@@ -72,10 +74,10 @@
         <Switch
             android:id="@+id/screenrecord_switch"
             android:layout_width="wrap_content"
-            android:minHeight="@dimen/screenrecord_option_icon_size"
             android:layout_height="wrap_content"
             android:gravity="center"
             android:layout_gravity="fill_vertical"
+            style="@style/ScreenRecord.Switch"
             android:layout_weight="0"
             android:contentDescription="@string/quick_settings_screen_record_label" />
     </LinearLayout>
@@ -112,11 +114,11 @@
         <Switch
             android:id="@+id/bugreport_switch"
             android:layout_width="wrap_content"
-            android:minHeight="@dimen/screenrecord_option_icon_size"
             android:layout_height="wrap_content"
             android:gravity="center"
             android:layout_gravity="fill_vertical"
             android:layout_weight="0"
+            style="@style/ScreenRecord.Switch"
             android:contentDescription="@string/qs_record_issue_bug_report" />
     </LinearLayout>
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_dialog_legacy.xml b/packages/SystemUI/res/layout/volume_dialog_legacy.xml
index 9010ab7..d44b6a8 100644
--- a/packages/SystemUI/res/layout/volume_dialog_legacy.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_legacy.xml
@@ -93,9 +93,7 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:background="@drawable/volume_background_bottom"
-                    android:paddingLeft="@dimen/volume_dialog_ringer_rows_padding"
-                    android:paddingBottom="@dimen/volume_dialog_ringer_rows_padding"
-                    android:paddingRight="@dimen/volume_dialog_ringer_rows_padding">
+                    android:paddingBottom="@dimen/volume_dialog_ringer_rows_padding">
                     <com.android.keyguard.AlphaOptimizedImageButton
                         android:id="@+id/settings"
                         android:src="@drawable/horizontal_ellipsis"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index ebee157..f095c0e 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Sluitskermlegstukke"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Om ’n app met ’n legstuk oop te maak, sal jy moet verifieer dat dit jy is. Hou ook in gedagte dat enigeen dit kan bekyk, selfs wanneer jou tablet gesluit is. Sommige legstukke is moontlik nie vir jou sluitskerm bedoel nie en dit kan onveilig wees om dit hier by te voeg."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Het dit"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Wissel gebruiker"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"aftrekkieslys"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle programme en data in hierdie sessie sal uitgevee word."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Word aan die bokant van gesprekskennisgewings en as \'n profielfoto op sluitskerm gewys, verskyn as \'n borrel, onderbreek Moenie Steur Nie"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> steun nie gesprekskenmerke nie"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Hierdie kennisgewings kan nie gewysig word nie."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Oproepkennisgewings kan nie gewysig word nie."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Hierdie groep kennisgewings kan nie hier opgestel word nie"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Keer die foon om vir hoër resolusie"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Voubare toestel word ontvou"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Voubare toestel word omgekeer"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Voorste skerm is aangeskakel"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"gevou"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"oopgevou"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Toeganklikheid"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Kortpadsleutels"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Pasmaak kortpadsleutels"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Druk sleutel om kortpad toe te wys"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Soekkortpaaie"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Geen soekresultate nie"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Vou ikoon in"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Sleephandvatsel"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Sleutelbordinstellings"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Stel kortpad"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Kanselleer"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Druk sleutel"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Sleutelkombinasie is reeds in gebruik. Probeer ’n ander sleutel."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigeer met jou sleutelbord"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Leer kortpadsleutels"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigeer met jou raakpaneel"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 0351c75..0bd9f1d 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"የማያ ገፅ ቁልፍ ምግብሮች"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ምግብር በመጠቀም መተግበሪያ ለመክፈት እርስዎ መሆንዎን ማረጋገጥ አለብዎት። እንዲሁም የእርስዎ ጡባዊ በተቆለፈበት ጊዜ እንኳን ማንኛውም ሰው እነሱን ማየት እንደሚችል ከግምት ውስጥ ያስገቡ። አንዳንድ ምግብሮች ለማያ ገፅ ቁልፍዎ የታሰቡ ላይሆኑ ይችላሉ እና እዚህ ለማከል አስተማማኝ ላይሆኑ ይችላሉ።"</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ገባኝ"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ተጠቃሚ ቀይር"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ወደታች ተጎታች ምናሌ"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"በዚህ ክፍለ-ጊዜ ውስጥ ያሉ ሁሉም መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"በውይይት ማሳወቂያዎች አናት ላይ እና በማያ ገፅ መቆለፊያ ላይ እንደ መገለጫ ምስል ይታያል፣ እንደ አረፋ ሆኖ ይታያል፣ አትረብሽን ያቋርጣል"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"ቅድሚያ"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> የውይይት ባህሪያትን አይደግፍም"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"እነዚህ ማሳወቂያዎች ሊሻሻሉ አይችሉም።"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"የጥሪ ማሳወቂያዎች ሊቀየሩ አይችሉም።"</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"የማሳወቂያዎች ይህ ቡድን እዚህ ላይ ሊዋቀር አይችልም"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"ለከፍተኛ ጥራት ስልኩን ይቀይሩ"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"መታጠፍ የሚችል መሣሪያ እየተዘረጋ ነው"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"መታጠፍ የሚችል መሣሪያ እየተገለበጠ ነው"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"የፊት ለፊት ማያ ገፅ በርቷል"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"የታጠፈ"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"የተዘረጋ"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ተደራሽነት"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"የቁልፍ ሰሌዳ አቋራጮች"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"የቁልፍ ሰሌዳ አቋራጮችን ያብጁ"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"አቋራጭ ለመመደብ ቁልፍ ይጫኑ"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"የፍለጋ አቋራጮች"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ምንም የፍለጋ ውጤቶች የሉም"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"መሰብሰቢያ አዶ"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"መያዣ ይጎትቱ"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"የቁልፍ ሰሌዳ ቅንብሮች"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"አቋራጭ አቀናብር"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ይቅር"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ቁልፍ ይጫኑ"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"የቁልፍ ጥምረት አስቀድሞ በሥራ ላይ ነው። ሌላ ቁልፍ ይሞክሩ።"</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"የቁልፍ ሰሌዳዎን በመጠቀም ያስሱ"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"የቁልፍ ሰሌዳ አቋራጮችን ይወቁ"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"የመዳሰሻ ሰሌዳዎን በመጠቀም ያስሱ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 645d880..bdd6139 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -113,7 +113,7 @@
     <string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"تسجيل شاشة تطبيق واحد"</string>
     <string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"تسجيل الشاشة بكاملها"</string>
     <string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="3754611651558838691">"‏تسجيل محتوى الشاشة بالكامل: %s"</string>
-    <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"أثناء تسجيل محتوى الشاشة بالكامل، يتم تسجيل كل المحتوى المعروض على شاشتك. لذا يُرجى توخي الحذر بشأن المعلومات، مثل كلمات المرور وتفاصيل الدفع والرسائل والصور وملفات الصوت والفيديو."</string>
+    <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"أثناء تسجيل محتوى الشاشة بالكامل، يتم تسجيل كل المحتوى المعروض على شاشتك، لذا يُرجى توخي الحذر بشأن المعلومات الظاهرة، مثل كلمات المرور وتفاصيل الدفع والرسائل والصور والمقاطع الصوتية والفيديوهات."</string>
     <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"سيتم تسجيل كل المحتوى المعروض أو المشغَّل على شاشة التطبيق، لذا يُرجى توخي الحذر بشأن المعلومات الظاهرة، مثل كلمات المرور وتفاصيل الدفع والرسائل والصور والمقاطع الصوتية والفيديوهات."</string>
     <string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"تسجيل الشاشة"</string>
     <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"يُرجى اختيار تطبيق لتسجيل شاشته"</string>
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"التطبيقات المصغّرة المصمَّمة لشاشة القفل"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"لفتح تطبيق باستخدام تطبيق مصغَّر، عليك إثبات هويتك. يُرجى ملاحظة أنّ أي شخص يمكنه الاطّلاع محتوى التطبيقات المصغَّرة، حتى وإن كان جهازك اللوحي مُقفلاً. بعض التطبيقات المصغّرة قد لا تكون مُصمَّمة لإضافتها إلى شاشة القفل، وقد يكون هذا الإجراء غير آمن."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"حسنًا"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تبديل المستخدم"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"القائمة المنسدلة"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"سيتم حذف كل التطبيقات والبيانات في هذه الجلسة."</string>
@@ -695,10 +699,10 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏%1$s. انقر للتجاهل. قد يتم تجاهل خدمات \"سهولة الاستخدام\"."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"‏%1$s. انقر للتعيين على الاهتزاز."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"‏%1$s. انقر لكتم الصوت."</string>
-    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"التحكُّم في مستوى الضوضاء"</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"التحكّم بالضوضاء"</string>
     <string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"الصوت المكاني"</string>
-    <string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"غير مفعّل"</string>
-    <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"تفعيل"</string>
+    <string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"عدم التفعيل"</string>
+    <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"التفعيل بدون تتبّع"</string>
     <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"تتبُّع حركة الرأس"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"انقر لتغيير وضع الرنين."</string>
     <string name="volume_ringer_mode" msgid="6867838048430807128">"وضع الرنين"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"تظهر في أعلى إشعارات المحادثات وكصورة ملف شخصي على شاشة القفل وتظهر على شكل فقاعة لمقاطعة ميزة \"عدم الإزعاج\"."</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"الأولوية"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"لا يدعم تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> ميزات المحادثات."</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"يتعذّر تعديل هذه الإشعارات."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"لا يمكن تعديل إشعارات المكالمات."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"يتعذّر ضبط مجموعة الإشعارات هذه هنا."</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"يجب استخدام أقل من <xliff:g id="LENGTH">%1$d</xliff:g> حرف."</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"رقم الإصدار"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"تم نسخ رقم الإصدار إلى الحافظة."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"نسخ المحتوى إلى الحافظة"</string>
     <string name="basic_status" msgid="2315371112182658176">"محادثة مفتوحة"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"التطبيقات المصغّرة للمحادثات"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"انقر على محادثة لإضافتها إلى \"الشاشة الرئيسية\""</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"للحصول على درجة دقة أعلى، اقلِب الهاتف."</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"جهاز قابل للطي يجري فتحه"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"جهاز قابل للطي يجري قلبه"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"تم تفعيل الشاشة الأمامية"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"مطوي"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"غير مطوي"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"‫%1$s / %2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"تسهيل الاستخدام"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"اختصارات لوحة المفاتيح"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"تخصيص اختصارات لوحة المفاتيح"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"اضغط على مفتاح لتخصيص الاختصار"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"البحث في الاختصارات"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ما مِن نتائج بحث"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"رمز التصغير"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"مقبض السحب"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"إعدادات لوحة المفاتيح"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ضبط الاختصار"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"إلغاء"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"اضغط على مفتاح"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"يتم حاليًا استخدام مجموعة المفاتيح هذه. يُرجى تجربة مفتاح آخر."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"التنقّل باستخدام لوحة المفاتيح"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"تعرَّف على اختصارات لوحة المفاتيح"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"التنقّل باستخدام لوحة اللمس"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index e14f4cc..631c43d 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"লক স্ক্ৰীন ৱিজেট"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"এটা ৱিজেট ব্যৱহাৰ কৰি কোনো এপ্ খুলিবলৈ, এয়া আপুনিয়েই বুলি সত্যাপন পৰীক্ষা কৰিব লাগিব। লগতে, মনত ৰাখিব যে যিকোনো লোকেই সেইবোৰ চাব পাৰে, আনকি আপোনাৰ টেবলেটটো লক হৈ থাকিলেও। কিছুমান ৱিজেট হয়তো আপোনাৰ লক স্ক্ৰীনৰ বাবে কৰা হোৱা নাই আৰু ইয়াত যোগ কৰাটো অসুৰক্ষিত হ’ব পাৰে।"</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"বুজি পালোঁ"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যৱহাৰকাৰী সলনি কৰক"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"পুল-ডাউনৰ মেনু"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই ছেশ্বনৰ আটাইবোৰ এপ্ আৰু ডেটা মচা হ\'ব।"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"বাৰ্তালাপৰ জাননীৰ শীৰ্ষত আৰু প্ৰ’ফাইল চিত্ৰ হিচাপে লক স্ক্ৰীনত দেখুৱায়, এটা বাবল হিচাপে দেখা পোৱা যায়, অসুবিধা নিদিব ম’ডত ব্যাঘাত জন্মায়"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"অগ্ৰাধিকাৰ"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বাৰ্তালাপৰ সুবিধাসমূহ সমৰ্থন নকৰে"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"এই জাননীসমূহ সংশোধন কৰিব নোৱাৰি।"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"কলৰ জাননীসমূহ সংশোধন কৰিব নোৱাৰি।"</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"এই ধৰণৰ জাননীবোৰ ইয়াত কনফিগাৰ কৰিব পৰা নাযায়"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"অধিক ৰিজ’লিউশ্বনৰ বাবে, ফ’নটো লুটিয়াই দিয়ক"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"জপাব পৰা ডিভাইচৰ জাপ খুলি থকা হৈছে"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"জপাব পৰা ডিভাইচৰ ওলোটাই থকা হৈছে"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"সন্মুখৰ স্ক্ৰীনখন অন কৰা হৈছে"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ফ’ল্ড কৰা"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"আনফ’ল্ড কৰা"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"সাধ্য সুবিধা"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"কীব’ৰ্ডৰ শ্বৰ্টকাট"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"কীব’ৰ্ডৰ শ্বৰ্টকাট কাষ্টমাইজ কৰক"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"শ্বৰ্টকাটৰ ভূমিকা অৰ্পণ কৰিবলৈ কী টিপক"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"সন্ধানৰ শ্বৰ্টকাট"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"সন্ধানৰ কোনো ফলাফল নাই"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"সংকোচন কৰাৰ চিহ্ন"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ড্ৰেগ হেণ্ডেল"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"কীব’ৰ্ডৰ ছেটিং"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"শ্বৰ্টকাট ছেট কৰক"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"বাতিল কৰক"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"কী টিপক"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"কীৰ মিশ্ৰণ ইতিমধ্যে ব্যৱহাৰ হৈ আছে। অন্য এটা কী ব্যৱহাৰ কৰি চাওক।"</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"কীব’ৰ্ড ব্যৱহাৰ কৰি নেভিগে’ট কৰক"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"কীব’ৰ্ডৰ শ্বৰ্টকাটসমূহৰ বিষয়ে জানক"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"আপোনাৰ টাচ্চপেড ব্যৱহাৰ কৰি নেভিগে’ট কৰক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 9016870..2b61f01 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Kilid ekranı vidcetləri"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Vidcetdən istifadə edərək tətbiqi açmaq üçün kimliyi doğrulamalısınız. Planşet kilidli olsa da, hər kəs vidcetlərə baxa bilər. Bəzi vidcetlər kilid ekranı üçün nəzərdə tutulmayıb və bura əlavə etmək təhlükəli ola bilər."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Anladım"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"aşağı çəkilən menyu"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu sessiyada bütün tətbiqlər və data silinəcək."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Söhbət bildirişlərinin yuxarısında və kilid ekranında profil şəkli kimi göstərilir, baloncuq kimi görünür, Narahat Etməyin rejimini kəsir"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> söhbət funksiyalarını dəstəkləmir"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirişlər dəyişdirilə bilməz."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Zəng bildirişləri dəyişdirilə bilməz."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Bu bildiriş qrupunu burada konfiqurasiya etmək olmaz"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Daha yüksək ayırdetmə dəqiqliyi üçün telefonu çevirin"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Qatlana bilən cihaz açılır"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Qatlana bilən cihaz fırladılır"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Ön ekran aktiv edildi"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"qatlanmış"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"açıq"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Xüsusi imkanlar"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Klaviatura qısayolları"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Klaviatura qısayollarını fərdiləşdirin"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Qısayol təyin etmək üçün düyməni basın"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Axtarış qısayolları"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Axtarış nəticəsi yoxdur"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"İkonanı yığcamlaşdırın"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Dəstəyi çəkin"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Klaviatura ayarları"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Qısayol ayarlayın"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Ləğv edin"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Düyməni basın"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Düymə kombinasiyası artıq istifadə olunur. Başqa düyməni sınayın."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Klaviaturadan istifadə edərək hərəkət edin"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Klaviatura qısayolları haqqında öyrənin"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Taçpeddən istifadə edərək hərəkət edin"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index d2636c0..c52824f 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Vidžeti za zaključani ekran"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Da biste otvorili aplikaciju koja koristi vidžet, treba da potvrdite da ste to vi. Imajte u vidu da svako može da ga vidi, čak i kada je tablet zaključan. Neki vidžeti možda nisu namenjeni za zaključani ekran i možda nije bezbedno da ih tamo dodate."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Važi"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zameni korisnika"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući meni"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji će biti izbrisani."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikazuje se u vrhu obaveštenja o konverzacijama i kao slika profila na zaključanom ekranu, pojavljuje se kao oblačić, prekida režim Ne uznemiravaj"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritetno"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava funkcije konverzacije"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ova obaveštenja ne mogu da se menjaju."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Obaveštenja o pozivima ne mogu da se menjaju."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ova grupa obaveštenja ne može da se konfiguriše ovde"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Koristite manji broj znakova od <xliff:g id="LENGTH">%1$d</xliff:g>"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u privremenu memoriju."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"kopirajte u privremenu memoriju."</string>
     <string name="basic_status" msgid="2315371112182658176">"Otvorite konverzaciju"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Vidžeti za konverzaciju"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Dodirnite konverzaciju da biste je dodali na početni ekran"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Za veću rezoluciju obrnite telefon"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Uređaj na preklop se otvara"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Uređaj na preklop se obrće"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Prednji ekran je uključen"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zatvoreno"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"otvoreno"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Pristupačnost"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Tasterske prečice"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prilagodite tasterske prečice"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Pritisnite taster da biste dodelili prečicu"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pretražite prečice"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nema rezultata pretrage"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za skupljanje"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Marker za prevlačenje"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Podešavanja tastature"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Podesi prečicu"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Otkaži"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pritisnite taster"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Kombinacija tastera se već koristi. Probajte sa drugim tasterom."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Krećite se pomoću tastature"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Saznajte više o tasterskim prečicama"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Krećite se pomoću tačpeda"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 388950c..a58b47c 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Віджэты на экране блакіроўкі"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Каб адкрыць праграму з дапамогай віджэта, вам неабходна будзе пацвердзіць сваю асобу. Таксама памятайце, што такія віджэты могуць пабачыць іншыя людзі, нават калі экран планшэта заблакіраваны. Некаторыя віджэты могуць не падыходзіць для выкарыстання на экране блакіроўкі, і дадаваць іх сюды можа быць небяспечна."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Зразумела"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Перайсці да іншага карыстальніка"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"высоўнае меню"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усе праграмы і даныя гэтага сеанса будуць выдалены."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"З’яўляецца ўверсе раздзела размоў як усплывальнае апавяшчэнне, якое перарывае рэжым \"Не турбаваць\" і паказвае на экране блакіроўкі відарыс профілю"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Прыярытэт"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не падтрымлівае функцыі размовы"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Гэтыя апавяшчэнні нельга змяніць."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Апавяшчэнні пра выклікі нельга змяніць."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Тут канфігурыраваць гэту групу апавяшчэнняў забаронена"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Каб зрабіць фота з больш высокай раздзяляльнасцю, павярніце тэлефон"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Складная прылада ў раскладзеным выглядзе"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Перавернутая складная прылада"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Пярэдні экран уключаны"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"складзена"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"раскладзена"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Спецыяльныя магчымасці"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Спалучэнні клавіш"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Наладзіць спалучэнні клавіш"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Націсніце клавішу, каб прызначыць спалучэнне клавіш"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Пошук спалучэнняў клавіш"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Няма вынікаў пошуку"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок \"Згарнуць\""</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Маркер перацягвання"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Налады клавіятуры"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Наладзіць спалучэнне клавіш"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Скасаваць"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Націсніце клавішу"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Гэта спалучэнне клавіш ужо выкарыстоўваецца. Паспрабуйце іншую клавішу."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Навігацыя з дапамогай клавіятуры"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Азнаёмцеся са спалучэннямі клавіш"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Навігацыя з дапамогай сэнсарнай панэлі"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 2d68f91..e847805 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Приспособления за заключения екран"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"За да отворите дадено приложение посредством приспособление, ще трябва да потвърдите, че това сте вие. Също така имайте предвид, че всеки ще вижда приспособленията дори когато таблетът ви е заключен. Възможно е някои от тях да не са предназначени за заключения екран и добавянето им на него може да е опасно."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Разбрах"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Превключване между потребителите"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"падащо меню"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Всички приложения и данни в тази сесия ще бъдат изтрити."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Показва се в горната част на известията за разговори и като снимка на потребителския профил на заключения екран, изглежда като балонче, прекъсва режима „Не безпокойте“"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддържа функциите за разговор"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Тези известия не могат да бъдат променяни."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Известията за обаждания не могат да бъдат променяни."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Тази група от известия не може да бъде конфигурирана тук"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Използвайте по-малко от <xliff:g id="LENGTH">%1$d</xliff:g> знака"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер на компилацията"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Номерът на компилацията е копиран в буферната памет."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"копиране в буферната памет."</string>
     <string name="basic_status" msgid="2315371112182658176">"Отворен разговор"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Приспособления за разговор"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Докоснете разговор, за да го добавите към началния си екран"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"За по-висока разделителна способност обърнете телефона"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Разгъване на сгъваемо устройство"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Обръщане на сгъваемо устройство"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Предният екран е включен"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"затворено"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"отворено"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Достъпност"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Клавишни комбинации"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Персонализиране на клавишните комбинации"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Натиснете клавиш, за да зададете клавишна комбинация"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Търсете клавишни комбинации"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Няма резултати от търсенето"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за свиване"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Манипулатор за преместване с плъзгане"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Настройки на клавиатурата"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Задаване на клавишна комбинация"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Отказ"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Натиснете клавиш"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Клавишната комбинация вече се използва. Опитайте с друг клавиш."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Навигирайте посредством клавиатурата си"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Научете за клавишните комбинации"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Навигирайте посредством сензорния панел"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 4281ea1..557edbe 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"লক স্ক্রিন উইজেট"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"উইজেট ব্যবহার করে কোনও অ্যাপ খুলতে, আপনাকে নিজের পরিচয় যাচাই করতে হবে। এছাড়াও, মনে রাখবেন, আপনার ট্যাবলেট লক থাকলেও যেকেউ তা দেখতে পারবেন। কিছু উইজেট আপনার লক স্ক্রিনের উদ্দেশ্যে তৈরি করা হয়নি এবং এখানে যোগ করা নিরাপদ নাও হতে পারে।"</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"বুঝেছি"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যবহারকারী পাল্টে দিন"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"পুলডাউন মেনু"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই সেশনের সব অ্যাপ ও ডেটা মুছে ফেলা হবে।"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"কথোপকথনের বিজ্ঞপ্তির উপরের দিকে এবং প্রোফাইল ছবি হিসেবে লক স্ক্রিনে দেখানো হয়, বাবল হিসেবেও এটি দেখা যায় এবং এর ফলে \'বিরক্ত করবে না\' মোডে কাজ করতে অসুবিধা হয়"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"অগ্রাধিকার"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এ কথোপকথন ফিচার কাজ করে না"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"এই বিজ্ঞপ্তিগুলি পরিবর্তন করা যাবে না।"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"কল বিজ্ঞপ্তি পরিবর্তন করা যাবে না।"</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"এই সমস্ত বিজ্ঞপ্তিকে এখানে কনফিগার করা যাবে না"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"আরও বেশি রেজোলিউশনের জন্য, ফোন ফ্লিপ করুন"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ফোল্ড করা যায় এমন ডিভাইস খোলা হচ্ছে"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ফোল্ড করা যায় এমন ডিভাইস উল্টানো হচ্ছে"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ফ্রন্ট স্ক্রিন চালু আছে"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ফোল্ড করা রয়েছে"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ফোল্ড করা নেই"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"অ্যাক্সেসিবিলিটি"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"কীবোর্ড শর্টকাট"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"কীবোর্ড শর্টকাট কাস্টমাইজ করুন"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"শর্টকাট অ্যাসাইন করতে কী প্রেস করুন"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"শর্টকাট সার্চ করুন"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"কোনও সার্চ ফলাফল নেই"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"আইকন আড়াল করুন"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"টেনে আনার হ্যান্ডেল"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"কীবোর্ড সেটিংস"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"শর্টকাট সেট করুন"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"বাতিল করুন"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"কী প্রেস করুন"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"কী কম্বিনেশন আগে থেকে ব্যবহার হচ্ছে। অন্য কী ব্যবহার করে দেখুন।"</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"আপনার কীবোর্ড ব্যবহার করে নেভিগেট করুন"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"কীবোর্ড শর্টকাট সম্পর্কে জানুন"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"আপনার টাচপ্যাড ব্যবহার করে নেভিগেট করুন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 9d9bf7f..ac4099f 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Vidžeti na zaključanom ekranu"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Da otvorite aplikaciju pomoću vidžeta, morat ćete potvrditi identitet. Također imajte na umu da ih svako može pregledati, čak i ako je tablet zaključan. Neki vidžeti možda nisu namijenjeni za vaš zaključani ekran i njihovo dodavanje ovdje možda nije sigurno."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Razumijem"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zamijeni korisnika"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući meni"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci iz ove sesije će se izbrisati."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikazuje se na vrhu obavještenja u razgovorima i kao slika profila na zaključanom ekranu, izgleda kao oblačić, prekida funkciju Ne ometaj"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritetno"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava funkcije razgovora"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ta obavještenja se ne mogu izmijeniti."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Nije moguće izmijeniti obavještenja o pozivima."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ovu grupu obavještenja nije moguće konfigurirati ovdje"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Za višu rezoluciju obrnite telefon"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Sklopivi uređaj se rasklapa"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Sklopivi uređaj se obrće"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Prednji ekran je uključen"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"sklopljeno"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"otklopljeno"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Pristupačnost"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Prečice tastature"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prilagodite prečice na tastaturi"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Pritisnite tipku da dodijelite prečicu"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečica pretraživanja"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nema rezultata pretraživanja"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona sužavanja"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Ručica za prevlačenje"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Postavke tastature"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Postavi prečicu"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Otkaži"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pritisnite tipku"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Ta se kombinacija tipki već koristi. Pokušajte s drugom tipkom."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Krećite se pomoću tastature"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Saznajte više o prečicama tastature"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Krećite se pomoću dodirne podloge"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 0be3d80..b5396da 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets de la pantalla de bloqueig"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Per obrir una aplicació utilitzant un widget, necessitaràs verificar la teva identitat. També has de tenir en compte que qualsevol persona pot veure els widgets, fins i tot quan la tauleta està bloquejada. És possible que alguns widgets no estiguin pensats per a la pantalla de bloqueig i que no sigui segur afegir-los-hi."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Entesos"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Canvia d\'usuari"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú desplegable"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Totes les aplicacions i les dades d\'aquesta sessió se suprimiran."</string>
@@ -715,7 +719,7 @@
     <string name="volume_panel_hint_muted" msgid="1124844870181285320">"silenciat"</string>
     <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibra"</string>
     <string name="media_output_label_title" msgid="872824698593182505">"S\'està reproduint <xliff:g id="LABEL">%s</xliff:g> a"</string>
-    <string name="media_output_title_without_playing" msgid="3825663683169305013">"Es reproduirà a"</string>
+    <string name="media_output_title_without_playing" msgid="3825663683169305013">"L\'àudio es reproduirà a"</string>
     <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Trucant des de"</string>
     <string name="system_ui_tuner" msgid="1471348823289954729">"Personalitzador d\'interfície d\'usuari"</string>
     <string name="status_bar" msgid="4357390266055077437">"Barra d\'estat"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Es mostra a la part superior de les notificacions de les converses i com a foto de perfil a la pantalla de bloqueig, apareix com una bombolla, interromp el mode No molestis"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritat"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet les funcions de converses"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Aquestes notificacions no es poden modificar."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Les notificacions de trucades no es poden modificar."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Aquest grup de notificacions no es pot configurar aquí"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Utilitza menys de <xliff:g id="LENGTH">%1$d</xliff:g> caràcters"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilació"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"El número de compilació s\'ha copiat al porta-retalls."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"copiar al porta-retalls."</string>
     <string name="basic_status" msgid="2315371112182658176">"Conversa oberta"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversa"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Toca una conversa per afegir-la a la teva pantalla d\'inici"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Per a una resolució més alta, gira el telèfon"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositiu plegable desplegant-se"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositiu plegable girant"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"La pantalla frontal està activada"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegat"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegat"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibilitat"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Tecles de drecera"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalitza les tecles de drecera"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Prem la tecla per assignar la drecera"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Dreceres de cerca"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No hi ha cap resultat de la cerca"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Replega la icona"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Ansa per arrossegar"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Configuració del teclat"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Configura la drecera"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel·la"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Prem una tecla"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"La combinació de tecles ja s\'està utilitzant. Prova-ho amb una altra tecla."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navega amb el teclat"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprèn les tecles de drecera"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navega amb el ratolí tàctil"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 1bbef7b..a6f0e61 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgety na obrazovce uzamčení"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"K otevření aplikace pomocí widgetu budete muset ověřit svou totožnost. Také mějte na paměti, že widgety uvidí kdokoli, i když tablet bude uzamčen. Některé widgety nemusí být pro obrazovku uzamčení určeny a nemusí být bezpečné je na ni přidat."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Rozumím"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Přepnout uživatele"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rozbalovací nabídka"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Veškeré aplikace a data v této relaci budou vymazána."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Zobrazuje se v horní části sekce konverzací a na obrazovce uzamčení se objevuje jako profilová fotka, má podobu bubliny a deaktivuje režim Nerušit"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritní"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> funkce konverzace nepodporuje"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Tato oznámení nelze upravit."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Upozornění na hovor nelze upravit."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Tuto skupinu oznámení tady nelze nakonfigurovat"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Použijte méně než <xliff:g id="LENGTH">%1$d</xliff:g> znaků"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo sestavení"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Číslo sestavení bylo zkopírováno do schránky."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"zkopírovat do schránky"</string>
     <string name="basic_status" msgid="2315371112182658176">"Otevřít konverzaci"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widgety konverzací"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Klepnutím na konverzaci ji přidáte na plochu"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Otočte telefon, abyste dosáhli vyššího rozlišení"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Rozkládání rozkládacího zařízení"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Otáčení rozkládacího zařízení"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Přední obrazovka je zapnutá"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"složené"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"rozložené"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Přístupnost"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Klávesové zkratky"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Přizpůsobení klávesových zkratek"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Nastavte zkratku stisknutím klávesy"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Vyhledat zkratky"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Žádné výsledky hledání"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona sbalení"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Úchyt pro přetažení"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Nastavení klávesnice"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Nastavit zkratku"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Zrušit"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Stiskněte klávesu"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Kombinace kláves se už používá. Použijte jinou klávesu."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigujte pomocí klávesnice"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Naučte se klávesové zkratky"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigujte pomocí touchpadu"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index b2e17a9..f5d36d7 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets på låseskærmen"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Hvis du vil åbne en app ved hjælp af en widget, skal du verificere din identitet. Husk også, at alle kan se dem, også når din tablet er låst. Nogle widgets er muligvis ikke beregnet til låseskærmen, og det kan være usikkert at tilføje dem her."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skift bruger"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullemenu"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps og data i denne session slettes."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Vises øverst i samtalenotifikationer og som et profilbillede på låseskærmen. Vises som en boble, der afbryder Forstyr ikke"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> understøtter ikke samtalefunktioner"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Disse notifikationer kan ikke redigeres."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Opkaldsnotifikationer kan ikke redigeres."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Du kan ikke konfigurere denne gruppe notifikationer her"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Vend telefonen for at få højere opløsning"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldbar enhed foldes ud"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldbar enhed vendes om"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Frontskærmen er aktiveret"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"foldet"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"foldet ud"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Hjælpefunktioner"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Tastaturgenveje"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Tilpas tastaturgenveje"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Tryk på en tast for at tildele genvejen"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Genveje til søgning"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Der er ingen søgeresultater"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikon for Skjul"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Håndtag"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Tastaturindstillinger"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Konfigurer genvej"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Annuller"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tryk på en tast"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Tastekombinationen er allerede i brug. Prøv en anden tast."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviger ved hjælp af dit tastatur"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Se tastaturgenveje"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviger ved hjælp af din touchplade"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 5f7128e..1573cb0 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Sperrbildschirm-Widgets"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Wenn du eine App mit einem Widget öffnen möchtest, musst du deine Identität bestätigen. Beachte auch, dass jeder die Widgets sehen kann, auch wenn dein Tablet gesperrt ist. Einige Widgets sind möglicherweise nicht für den Sperrbildschirm vorgesehen, sodass es unsicher sein kann, sie hier hinzuzufügen."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ok"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Nutzer wechseln"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"Pull-down-Menü"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Wird oben im Bereich „Unterhaltungen“ sowie als Profilbild auf dem Sperrbildschirm angezeigt, erscheint als Bubble, unterbricht „Bitte nicht stören“"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Priorität"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> unterstützt keine Funktionen für Unterhaltungen"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Diese Benachrichtigungen können nicht geändert werden."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Anrufbenachrichtigungen können nicht geändert werden."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Die Benachrichtigungsgruppe kann hier nicht konfiguriert werden"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Für höhere Auflösung Smartphone umdrehen"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Faltbares Gerät wird geöffnet"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Faltbares Gerät wird umgeklappt"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Frontdisplay aktiviert"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zugeklappt"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aufgeklappt"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Bedienungshilfen"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Tastenkürzel"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Tastenkombinationen anpassen"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Drücke eine Taste, um eine Tastenkombination festzulegen"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Tastenkürzel suchen"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Keine Suchergebnisse"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Symbol „Minimieren“"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Ziehpunkt"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Tastatureinstellungen"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Tastenkombination festlegen"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Abbrechen"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Taste drücken"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Diese Tastenkombination wird bereits verwendet. Versuche es mit einer anderen Taste."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigation mit der Tastatur"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Informationen zu Tastenkombinationen"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigation mit dem Touchpad"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index fd8e37a..8da3214 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Γραφικά στοιχεία οθόνης κλειδώματος"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Για να ανοίξετε μια εφαρμογή χρησιμοποιώντας ένα γραφικό στοιχείο, θα πρέπει να επαληθεύσετε την ταυτότητά σας. Επίσης, λάβετε υπόψη ότι η προβολή τους είναι δυνατή από οποιονδήποτε, ακόμα και όταν το tablet σας είναι κλειδωμένο. Ορισμένα γραφικά στοιχεία μπορεί να μην προορίζονται για την οθόνη κλειδώματος και η προσθήκη τους εδώ ενδέχεται να μην είναι ασφαλής."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Το κατάλαβα"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Εναλλαγή χρήστη"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"αναπτυσσόμενο μενού"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Όλες οι εφαρμογές και τα δεδομένα αυτής της περιόδου σύνδεσης θα διαγραφούν."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Εμφανίζεται στην κορυφή των ειδοποιήσεων συζήτησης και ως φωτογραφία προφίλ στην οθόνη κλειδώματος, εμφανίζεται ως συννεφάκι, διακόπτει τη λειτουργία Μην ενοχλείτε"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Προτεραιότητα"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν υποστηρίζει τις λειτουργίες συζήτησης"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Δεν είναι δυνατή η τροποποίηση αυτών των ειδοποιήσεων"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Δεν είναι δυνατή η τροποποίηση των ειδοποιήσεων κλήσεων."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Δεν είναι δυνατή η διαμόρφωση αυτής της ομάδας ειδοποιήσεων εδώ"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Χρησιμοποιήστε λιγότερους από <xliff:g id="LENGTH">%1$d</xliff:g> χαρακτήρες"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Αριθμός έκδοσης"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Ο αριθμός έκδοσης αντιγράφηκε στο πρόχειρο."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"αντιγραφή στο πρόχειρο."</string>
     <string name="basic_status" msgid="2315371112182658176">"Άνοιγμα συνομιλίας"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Γραφικά στοιχεία συνομιλίας"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Πατήστε μια συνομιλία για να την προσθέσετε στην αρχική οθόνη"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Για υψηλότερη ανάλυση, αναστρέψτε το τηλέφωνο"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Αναδιπλούμενη συσκευή που ξεδιπλώνει"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Αναδιπλούμενη συσκευή που διπλώνει"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Η μπροστινή οθόνη ενεργοποιήθηκε"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"διπλωμένη"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ξεδιπλωμένη"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Προσβασιμότητα"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Συντομεύσεις πληκτρολογίου"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Προσαρμογή συντομεύσεων πληκτρολογίου"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Πατήστε το πλήκτρο για εκχώρηση της συντόμευσης"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Συντομεύσεις αναζήτησης"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Κανένα αποτέλεσμα αναζήτησης"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Εικονίδιο σύμπτυξης"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Λαβή μεταφοράς"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Ρυθμίσεις πληκτρολογίου"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Ορισμός συντόμευσης"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Ακύρωση"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Πατήστε ένα πλήκτρο"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Ο συνδυασμός πλήκτρων χρησιμοποιείται ήδη. Δοκιμάστε άλλο πλήκτρο."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Πλοήγηση με το πληκτρολόγιο"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Μάθετε συντομεύσεις πληκτρολογίου"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Πλοήγηση με την επιφάνεια αφής"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 4280ff2..e92783d 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lock screen widgets"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"To open an app using a widget, you\'ll need to verify that it\'s you. Also, bear in mind that anyone can view them, even when your tablet\'s locked. Some widgets may not have been intended for your lock screen and may be unsafe to add here."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Got it"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Call notifications can\'t be modified."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use fewer than <xliff:g id="LENGTH">%1$d</xliff:g> characters"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"copy to clipboard."</string>
     <string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Conversation widgets"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Tap a conversation to add it to your home screen"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"For higher resolution, flip the phone"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Front screen turned on"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibility"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Keyboard shortcuts"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Customise keyboard shortcuts"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Press key to assign shortcut"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No search results"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Drag handle"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Keyboard settings"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Set shortcut"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Press key"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Key combination already in use. Try another key."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigate using your keyboard"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Learn keyboards shortcuts"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigate using your touchpad"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 3b009a1..b434c6e 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -528,6 +528,8 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lock screen widgets"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"To open an app using a widget, you’ll need to verify it’s you. Also, keep in mind that anyone can view them, even when your tablet’s locked. Some widgets may not have been intended for your lock screen and may be unsafe to add here."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Got it"</string>
+    <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string>
+    <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="511359420883794513">"To add Widgets on the lock screen as a shortcut, make sure it is enabled in settings."</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
@@ -780,6 +782,7 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
+    <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Provide Bundle Feedback"</string>
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Call notifications can\'t be modified."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string>
@@ -1220,8 +1223,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use fewer than <xliff:g id="LENGTH">%1$d</xliff:g> characters"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"copy to clipboard."</string>
     <string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Conversation widgets"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Tap a conversation to add it to your Home screen"</string>
@@ -1417,7 +1419,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibility"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Keyboard shortcuts"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Customize keyboard shortcuts"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Press key to assign shortcut"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No search results"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
@@ -1430,9 +1437,13 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Drag handle"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Keyboard Settings"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Set shortcut"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Press key"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Key combination already in use. Try another key."</string>
+    <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Key combination already in use. Try another key."</string>
+    <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Shortcut cannot be set."</string>
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigate using your keyboard"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Learn keyboards shortcuts"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigate using your touchpad"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 4280ff2..e92783d 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lock screen widgets"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"To open an app using a widget, you\'ll need to verify that it\'s you. Also, bear in mind that anyone can view them, even when your tablet\'s locked. Some widgets may not have been intended for your lock screen and may be unsafe to add here."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Got it"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Call notifications can\'t be modified."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use fewer than <xliff:g id="LENGTH">%1$d</xliff:g> characters"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"copy to clipboard."</string>
     <string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Conversation widgets"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Tap a conversation to add it to your home screen"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"For higher resolution, flip the phone"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Front screen turned on"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibility"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Keyboard shortcuts"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Customise keyboard shortcuts"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Press key to assign shortcut"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No search results"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Drag handle"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Keyboard settings"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Set shortcut"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Press key"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Key combination already in use. Try another key."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigate using your keyboard"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Learn keyboards shortcuts"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigate using your touchpad"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 4280ff2..e92783d 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lock screen widgets"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"To open an app using a widget, you\'ll need to verify that it\'s you. Also, bear in mind that anyone can view them, even when your tablet\'s locked. Some widgets may not have been intended for your lock screen and may be unsafe to add here."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Got it"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Call notifications can\'t be modified."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use fewer than <xliff:g id="LENGTH">%1$d</xliff:g> characters"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"copy to clipboard."</string>
     <string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Conversation widgets"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Tap a conversation to add it to your home screen"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"For higher resolution, flip the phone"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Front screen turned on"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibility"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Keyboard shortcuts"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Customise keyboard shortcuts"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Press key to assign shortcut"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No search results"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Drag handle"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Keyboard settings"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Set shortcut"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Press key"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Key combination already in use. Try another key."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigate using your keyboard"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Learn keyboards shortcuts"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigate using your touchpad"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index ad403b1..4ab2f2b 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets en la pantalla de bloqueo"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir una app usando un widget, debes verificar tu identidad. Además, ten en cuenta que cualquier persona podrá verlo, incluso cuando la tablet esté bloqueada. Es posible que algunos widgets no se hayan diseñados para la pantalla de bloqueo y podría ser peligroso agregarlos allí."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Entendido"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú expandible"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán las aplicaciones y los datos de esta sesión."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Aparece en forma de burbuja y como foto de perfil en la parte superior de las notificaciones de conversación, en la pantalla de bloqueo, y detiene el modo No interrumpir"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritaria"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite funciones de conversación"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"No se pueden modificar estas notificaciones."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"No se pueden modificar las notificaciones de llamada."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"No se puede configurar aquí este grupo de notificaciones"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Usa menos de <xliff:g id="LENGTH">%1$d</xliff:g> caracteres"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Se copió el número de compilación en el portapapeles."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"copiar en el portapapeles."</string>
     <string name="basic_status" msgid="2315371112182658176">"Conversación abierta"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversación"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Presiona una conversación para agregarla a tu pantalla principal"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accesibilidad"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Combinaciones de teclas"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personaliza las combinaciones de teclas"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Presiona la tecla para asignar el acceso directo"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Buscar combinaciones de teclas"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"La búsqueda no arrojó resultados"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícono de contraer"</string>
@@ -1431,9 +1441,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Controlador de arrastre"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Configuración del teclado"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Establecer combinación de teclas"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Presiona una tecla"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"La combinación de teclas ya está en uso. Prueba con otra."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navega con el teclado"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprende combinaciones de teclas"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navega con el panel táctil"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 50de6d2..861d21e 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets para la pantalla de bloqueo"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir una aplicación usando un widget, deberás verificar que eres tú. Además, ten en cuenta que cualquier persona podrá verlos, incluso aunque tu tablet esté bloqueada. Es posible que algunos widgets no estén pensados para la pantalla de bloqueo y no sea seguro añadirlos aquí."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Entendido"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar de usuario"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú desplegable"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán todas las aplicaciones y datos de esta sesión."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Se muestra encima de las notificaciones de conversaciones y como imagen de perfil en la pantalla de bloqueo, aparece como burbuja e interrumpe el modo No molestar"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioridad"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite funciones de conversación"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificaciones no se pueden modificar."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Las notificaciones de llamada no se pueden modificar."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Este grupo de notificaciones no se puede configurar aquí"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Para una mayor resolución, gira el teléfono"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo plegable desplegándose"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo plegable mostrado desde varios ángulos"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Pantalla frontal encendida"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegado"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegado"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accesibilidad"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Combinaciones de teclas"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizar las combinaciones de teclas"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Pulsa una tecla para asignar una combinación de teclas"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atajos de búsqueda"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No hay resultados de búsqueda"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icono de contraer"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Controlador de arrastre"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Ajustes del teclado"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Establecer combinación de teclas"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pulsa una tecla"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"La combinación de teclas ya se está usando. Prueba con otra tecla."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Desplázate con el teclado"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprende combinaciones de teclas"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Desplázate con el panel táctil"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 9c0d56d..c2b1405 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lukustuskuva vidinad"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Rakenduse avamiseks vidina abil peate kinnitama, et see olete teie. Samuti pidage meeles, et kõik saavad vidinaid vaadata, isegi kui teie tahvelarvuti on lukus. Mõni vidin ei pruugi olla ette nähtud teie lukustuskuva jaoks ja seda pole turvaline siia lisada."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Selge"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kasutaja vahetamine"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rippmenüü"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Seansi kõik rakendused ja andmed kustutatakse."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Kuvatakse mullina vestluste märguannete ülaosas ja profiilipildina lukustuskuval ning katkestab režiimi Mitte segada"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioriteetne"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei toeta vestlusfunktsioone"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Neid märguandeid ei saa muuta."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Kõnemärguandeid ei saa muuta."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Seda märguannete rühma ei saa siin seadistada"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Kasutage vähem kui <xliff:g id="LENGTH">%1$d</xliff:g> tähemärki"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Järgunumber"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Järgunumber kopeeriti lõikelauale."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"lõikelauale kopeerimine."</string>
     <string name="basic_status" msgid="2315371112182658176">"Avage vestlus"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Vestlusvidinad"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Puudutage vestlust, et lisada see oma avakuvale"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Suurema eraldusvõime saavutamiseks pöörake telefon ümber"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Volditava seadme lahtivoltimine"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Volditava seadme ümberpööramine"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Esiekraan on sisse lülitatud"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kokku volditud"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"lahti volditud"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Juurdepääsetavus"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Klaviatuuri otseteed"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Klaviatuuri otseteede kohandamine"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Otsetee lisamiseks vajutage klahvi"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Otsige otseteid"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Otsingutulemused puuduvad"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ahendamisikoon"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Lohistamispide"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Klaviatuuri seaded"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Määrake otsetee"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Tühista"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Vajutage klahvi"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Klahvikombinatsioon juba kasutusel. Proovige mõnda muud klahvi."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigeerige klaviatuuri abil"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Õppige klaviatuuri otseteid"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigeerige puuteplaadi abil"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index a971d1c..7b9a0ea 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Pantaila blokeatuko widgetak"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Aplikazio bat widget baten bidez irekitzeko, zeu zarela egiaztatu beharko duzu. Gainera, kontuan izan edonork ikusi ahalko dituela halako widgetak, tableta blokeatuta badago ere. Baliteke widget batzuk pantaila blokeaturako egokiak ez izatea, eta agian ez da segurua haiek bertan gehitzea."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ados"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Aldatu erabiltzailea"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"zabaldu menua"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Saioko aplikazio eta datu guztiak ezabatuko dira."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Elkarrizketen jakinarazpenen goialdean eta profileko argazki gisa agertzen da pantaila blokeatuan, burbuila batean, eta ez molestatzeko modua eteten du"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Lehentasuna"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak ez ditu onartzen elkarrizketetarako eginbideak"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Jakinarazpen horiek ezin dira aldatu."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Deien jakinarazpenak ezin dira aldatu."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Jakinarazpen talde hau ezin da konfiguratu hemen"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Irauli telefonoa bereizmen handiago a lortzeko"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Gailu tolesgarria zabaltzen"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Gailu tolesgarria biratzen"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Aurreko pantaila piztuta dago"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"tolestuta"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"tolestu gabe"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Erabilerraztasuna"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Lasterbideak"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Pertsonalizatu lasterbideak"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Sakatu tekla lasterbidea esleitzeko"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Bilatu lasterbideak"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ez dago bilaketa-emaitzarik"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Tolesteko ikonoa"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Arrastatzeko kontrol-puntua"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Teklatuaren ezarpenak"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Ezarri lasterbidea"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Utzi"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Sakatu tekla"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Tekla-konbinazio hori erabili da dagoeneko. Probatu beste tekla bat."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Nabigatu teklatua erabilita"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Ikasi lasterbideak"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Nabigatu ukipen-panela erabilita"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index bf7ccf0..5401698 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ابزاره‌های صفحه قفل"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"برای باز کردن برنامه بااستفاده از ابزاره، باید هویت خودتان را به‌تأیید برسانید. همچنین، به‌خاطر داشته باشید که همه می‌توانند آن‌ها را مشاهده کنند، حتی وقتی رایانه لوحی‌تان قفل است. برخی‌از ابزاره‌ها ممکن است برای صفحه قفل درنظر گرفته نشده باشند و ممکن است اضافه کردن آن‌ها در اینجا ناامن باشد."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"متوجه‌ام"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تغییر کاربر"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"منوی پایین‌پر"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"همه برنامه‌ها و داده‌های این جلسه حذف خواهد شد."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"در بالای اعلان‌های مکالمه و به‌صورت عکس نمایه در صفحه قفل نشان داده می‌شود، به‌صورت حبابک ظاهر می‌شود، در حالت «مزاحم نشوید» وقفه ایجاد می‌کند"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"اولویت"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> از ویژگی‌های مکالمه پشتیبانی نمی‌کند"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"این اعلان‌ها قابل اصلاح نیستند."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"این اعلان‌ها قابل‌اصلاح نیستند."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"نمی‌توانید این گروه اعلان‌ها را در اینجا پیکربندی کنید"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"از کمتر از <xliff:g id="LENGTH">%1$d</xliff:g> نویسه استفاده کنید"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"شماره ساخت"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"شماره ساخت در بریده‌دان کپی شد."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"کپی کردن در بریده‌دان."</string>
     <string name="basic_status" msgid="2315371112182658176">"باز کردن مکالمه"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"ابزارک‌های مکالمه"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"روی مکالمه‌ای تک‌ضرب بزنید تا به «صفحه اصلی» اضافه شود"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"برای وضوح بیشتر، تلفن را بچرخانید"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"دستگاه تاشو درحال باز شدن"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"دستگاه تاشو درحال چرخش به اطراف"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"صفحه‌نمایش جلو روشن شد"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"تاشده"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"تانشده"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"دسترس‌پذیری"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"میان‌برهای صفحه‌کلید"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"سفارشی‌سازی کردن میان‌برهای صفحه‌کلید"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"برای اختصاص دادن میان‌بر، کلید را فشار دهید"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"جستجوی میان‌برها"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"نتیجه‌ای برای جستجو پیدا نشد"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"نماد جمع کردن"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"دستگیره کشاندن"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"تنظیمات صفحه‌کلید"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"تنظیم میان‌بر"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"لغو"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"کلید را فشار دهید"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"ترکیب کلید ازقبل درحال استفاده است. کلید دیگری را امتحان کنید."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"پیمایش کردن بااستفاده از صفحه‌کلید"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"آشنایی با میان‌برهای صفحه‌کلید"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"پیمایش کردن بااستفاده از صفحه لمسی"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 89ed95f..58b86fa 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lukitusnäytön widgetit"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Jos haluat avata sovelluksen käyttämällä widgetiä, sinun täytyy vahvistaa henkilöllisyytesi. Muista myös, että widgetit näkyvät kaikille, vaikka tabletti olisi lukittuna. Jotkin widgetit on ehkä tarkoitettu lukitusnäytölle, ja niiden lisääminen tänne ei välttämättä ole turvallista."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Selvä"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Vaihda käyttäjää"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"alasvetovalikko"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Kaikki sovellukset ja tämän istunnon tiedot poistetaan."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Näkyy keskusteluilmoitusten yläosassa ja profiilikuvana lukitusnäytöllä, näkyy kuplana, keskeyttää Älä häiritse ‑tilan"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Tärkeä"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei tue keskusteluominaisuuksia"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Näitä ilmoituksia ei voi muokata"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Puheluilmoituksia ei voi muokata."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Tätä ilmoitusryhmää ei voi määrittää tässä"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Resoluutio on parempi, kun käännät puhelimen"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Taitettava laite taitetaan"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Taitettava laite käännetään ympäri"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Etunäyttö päällä"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"taitettu"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"taittamaton"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Saavutettavuus"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Pikanäppäimet"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Pikanäppäimien muokkaaminen"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Määritä pikanäppäin painamalla näppäintä"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pikahaut"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ei hakutuloksia"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Tiivistyskuvake"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Vetokahva"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Näppäimistön asetukset"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Valitse pikanäppäin"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Peru"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Paina näppäintä"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Näppäinyhdistelmä on jo käytössä. Kokeile toista näppäintä."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Siirry käyttämällä näppäimistöä"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Opettele pikanäppäimiä"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Siirry käyttämällä kosketuslevyä"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 708d8b9..ff3da65 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets de l\'écran de verrouillage"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Pour ouvrir une appli à l\'aide d\'un widget, vous devrez confirmer votre identité. En outre, gardez à l\'esprit que tout le monde peut voir les widgets, même lorsque votre tablette est verrouillée. Certains widgets n\'ont peut-être pas été conçus pour votre écran de verrouillage, et il pourrait être dangereux de les ajouter ici."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu déroulant"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applis et les données de cette session seront supprimées."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"S\'affiche dans le haut des notifications de conversation et comme photo de profil à l\'écran de verrouillage, s\'affiche comme bulle, interrompt le mode Ne pas déranger"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritaire"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne prend pas en charge les fonctionnalités de conversation"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ces notifications ne peuvent pas être modifiées"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Les notifications d\'appel ne peuvent pas être modifiées."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ce groupe de notifications ne peut pas être configuré ici"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Pour une meilleure résolution, retournez le téléphone"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Appareil pliable en cours de dépliage"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Appareil pliable en train d\'être retourné"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Écran avant activé"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plié"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"déplié"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibilité"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Raccourcis-clavier"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personnaliser les raccourcis-clavier"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Appuyez sur la touche pour attribuer un raccourci"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Rechercher des raccourcis"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Aucun résultat de recherche"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icône Réduire"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Poignée de déplacement"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Paramètres du clavier"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Définir un raccourci"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Annuler"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Appuyez sur la touche"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Combinaison de touches déjà utilisée. Essayez une autre touche."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviguer à l\'aide de votre clavier"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Apprenez à utiliser les raccourcis-clavier"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviguer à l\'aide de votre pavé tactile"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 41bd910..e51cb07 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets pour l\'écran de verrouillage"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Pour ouvrir une appli à l\'aide d\'un widget, vous devez confirmer qu\'il s\'agit bien de vous. N\'oubliez pas non plus que tout le monde peut voir vos widgets, même lorsque votre tablette est verrouillée. Certains d\'entre eux n\'ont pas été conçus pour l\'écran de verrouillage et les ajouter à cet endroit peut s\'avérer dangereux."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu déroulant"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"S\'affiche en haut des notifications de conversation et en tant que photo de profil sur l\'écran de verrouillage, apparaît sous forme de bulle, interrompt le mode Ne pas déranger"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritaire"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec les fonctionnalités de conversation"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossible de modifier ces notifications."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Impossible de modifier les notifications d\'appel."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Vous ne pouvez pas configurer ce groupe de notifications ici"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Pour une résolution plus élevée, retournez le téléphone"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Appareil pliable qui est déplié"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Appareil pliable qui est retourné"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Écran avant activé"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plié"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"déplié"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibilité"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Raccourcis clavier"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personnaliser les raccourcis clavier"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Appuyez sur une touche pour attribuer un raccourci"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Rechercher des raccourcis"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Aucun résultat de recherche"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icône Réduire"</string>
@@ -1431,15 +1441,22 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Poignée de déplacement"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Paramètres du clavier"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Définir un raccourci"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Annuler"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Appuyez sur la touche"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Combinaison de touches déjà utilisée. Essayez une autre touche."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviguer à l\'aide du clavier"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Apprenez à utiliser les raccourcis clavier"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviguer à l\'aide de votre pavé tactile"</string>
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Découvrez les gestes au pavé tactile"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Naviguer à l\'aide de votre clavier et de votre pavé tactile"</string>
-    <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Découvrir les gestes au pavé tactile, les raccourcis clavier et plus encore"</string>
+    <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Découvrir les gestes du pavé tactile, les raccourcis clavier et plus encore"</string>
     <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Retour"</string>
     <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Retour à l\'accueil"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Afficher les applis récentes"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 3983606..6a1aced1 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets da pantalla de bloqueo"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir unha aplicación mediante un widget, tes que verificar a túa identidade. Ten en conta que pode velos calquera persoa, mesmo coa tableta bloqueada. Pode ser que algúns widgets non estean pensados para a túa pantalla de bloqueo, polo que talvez non sexa seguro engadilos aquí."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Entendido"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú despregable"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Eliminaranse todas as aplicacións e datos desta sesión."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Móstrase na parte superior das notificacións das conversas e como imaxe do perfil na pantalla de bloqueo, aparece como unha burbulla e interrompe o modo Non molestar"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> non admite funcións de conversa"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificacións non se poden modificar."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"As notificacións de chamadas non se poden modificar."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Aquí non se pode configurar este grupo de notificacións"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Dálle a volta ao teléfono para gozar dunha maior resolución"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo pregable abríndose"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo pregable xirando"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Activouse a pantalla dianteira"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"dispositivo pregado"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"dispositivo despregado"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accesibilidade"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Atallos de teclado"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizar os atallos de teclado"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Preme a tecla para asignar o atallo"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Busca atallos"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Non hai resultados de busca"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icona de contraer"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Controlador de arrastre"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Configuración do teclado"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Definir atallo"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Preme unha tecla"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Xa se está usando esta combinación de teclas. Proba con outra."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navega co teclado"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprende a usar os atallos de teclado"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navega co panel táctil"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 8901269..566ccd0 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"લૉક સ્ક્રીન વિજેટ"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"વિજેટનો ઉપયોગ કરીને ઍપ ખોલવા માટે, તમારે એ ચકાસણી કરવાની જરૂર રહેશે કે આ તમે જ છો. તે ઉપરાંત, ધ્યાનમાં રાખો કે તમારું ટૅબ્લેટ લૉક કરેલું હોય તો પણ કોઈપણ વ્યક્તિ તેમને જોઈ શકે છે. અમુક વિજેટ કદાચ તમારી લૉક સ્ક્રીન માટે બનાવવામાં આવ્યા ન હોઈ શકે છે અને તેમને અહીં ઉમેરવાનું અસલામત હોઈ શકે છે."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"સમજાઈ ગયું"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"વપરાશકર્તા સ્વિચ કરો"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"પુલડાઉન મેનૂ"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"આ સત્રમાંની તમામ ઍપ અને ડેટા કાઢી નાખવામાં આવશે."</string>
@@ -672,9 +676,9 @@
     <string name="screen_pinning_negative" msgid="6882816864569211666">"ના, આભાર"</string>
     <string name="screen_pinning_start" msgid="7483998671383371313">"ઍપ પિન કરી"</string>
     <string name="screen_pinning_exit" msgid="4553787518387346893">"ઍપ અનપિન કરી"</string>
-    <string name="stream_voice_call" msgid="7468348170702375660">"કૉલ કરો"</string>
+    <string name="stream_voice_call" msgid="7468348170702375660">"કૉલ"</string>
     <string name="stream_system" msgid="7663148785370565134">"સિસ્ટમ"</string>
-    <string name="stream_ring" msgid="7550670036738697526">"રિંગ વગાડો"</string>
+    <string name="stream_ring" msgid="7550670036738697526">"રિંગ"</string>
     <string name="stream_music" msgid="2188224742361847580">"મીડિયા"</string>
     <string name="stream_alarm" msgid="16058075093011694">"અલાર્મ"</string>
     <string name="stream_notification" msgid="7930294049046243939">"નોટિફિકેશન"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"વાતચીતના નોટિફિકેશન વિભાગની ટોચ પર અને લૉક કરેલી સ્ક્રીન પર પ્રોફાઇલ ફોટો તરીકે બતાવે છે, બબલ તરીકે દેખાય છે, ખલેલ પાડશો નહીં મોડમાં વિક્ષેપ ઊભો કરે છે"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"પ્રાધાન્યતા"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> વાતચીતની સુવિધાઓને સપોર્ટ આપતી નથી"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"આ નોટિફિકેશનમાં કોઈ ફેરફાર થઈ શકશે નહીં."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"કૉલના નોટિફિકેશનમાં કોઈ ફેરફાર કરી શકાતો નથી."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"નોટિફિકેશનના આ ગ્રૂપની ગોઠવણી અહીં કરી શકાશે નહીં"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"વધુ રિઝોલ્યુશન માટે, ફોનને ફ્લિપ કરો"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ફોલ્ડ કરી શકાય એવું ડિવાઇસ અનફોલ્ડ કરવામાં આવી રહ્યું છે"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ફોલ્ડ કરી શકાય એવું ડિવાઇસ ફ્લિપ કરવામાં આવી રહ્યું છે"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ફ્રન્ટ સ્ક્રીનની સુવિધા ચાલુ કરેલી છે"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ફોલ્ડ કરેલું"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"અનફોલ્ડ કરેલું"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ઍક્સેસિબિલિટી"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"કીબોર્ડ શૉર્ટકટ"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"કીબોર્ડ શૉર્ટકટને કસ્ટમાઇઝ કરો"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"શૉર્ટકટ સોંપવા માટે દી દબાવો"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"શૉર્ટકટ શોધો"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"કોઈ શોધ પરિણામો નથી"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"\'નાનું કરો\'નું આઇકન"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ઑબ્જેક્ટ ખેંચવાનું હૅન્ડલ"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"કીબોર્ડના સેટિંગ"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"શૉર્ટકટ સેટ કરો"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"રદ કરો"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"કી દબાવો"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"કી સંયોજન પેહલેથી ઉપયોગમાં છે. અન્ય કી અજમાવી જુઓ."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"તમારા કીબોર્ડ વડે નૅવિગેટ કરો"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"કીબોર્ડ શૉર્ટકર્ટ જાણો"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"તમારા ટચપૅડ વડે નૅવિગેટ કરો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 241e2e6..255fdc5 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"लॉक स्क्रीन विजेट"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"किसी विजेट से कोई ऐप्लिकेशन खोलने के लिए, आपको अपनी पहचान की पुष्टि करनी होगी. ध्यान रखें कि आपके टैबलेट के लॉक होने पर भी, कोई व्यक्ति विजेट देख सकता है. ऐसा हो सकता है कि कुछ विजेट, लॉक स्क्रीन पर दिखाने के लिए न बने हों. इन्हें लॉक स्क्रीन पर जोड़ना असुरक्षित हो सकता है."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ठीक है"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"उपयोगकर्ता बदलें"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेन्यू"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"इस सेशन के सभी ऐप्लिकेशन और डेटा को हटा दिया जाएगा."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"यह कई तरीकों से दिखती है, जैसे कि बातचीत वाली सूचनाओं में सबसे ऊपर, बबल के तौर पर, और लॉक स्क्रीन पर प्रोफ़ाइल फ़ोटो के तौर पर. साथ ही, यह \'परेशान न करें\' मोड को बायपास कर सकती है"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> पर बातचीत की सुविधाएं काम नहीं करतीं"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"ये सूचनाएं नहीं बदली जा सकती हैं."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"कॉल से जुड़ी सूचनाओं को ब्लॉक नहीं किया जा सकता."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"सूचनाओं के इस समूह को यहां कॉन्फ़िगर नहीं किया जा सकता"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> वर्ण से कम इस्तेमाल करें"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर को क्लिपबोर्ड पर कॉपी किया गया."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"क्लिपबोर्ड पर कॉपी करें."</string>
     <string name="basic_status" msgid="2315371112182658176">"ऐसी बातचीत जिसमें इंटरैक्शन डेटा मौजूद नहीं है"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"बातचीत वाला विजेट"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"किसी बातचीत को होम स्क्रीन पर जोड़ने के लिए, उस बातचीत पर टैप करें"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"बेहतर रिज़ॉल्यूशन वाली फ़ोटो खींचने के लिए, फ़ोन को फ़्लिप करें"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"फ़ोल्ड किया जा सकने वाला डिवाइस अनफ़ोल्ड किया जा रहा है"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"फ़ोल्ड किया जा सकने वाला डिवाइस पलटा जा रहा है"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"फ़्रंट स्क्रीन चालू है"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"डिवाइस फ़ोल्ड किया गया"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"डिवाइस अनफ़ोल्ड किया गया"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"सुलभता"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"कीबोर्ड शॉर्टकट"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"कीबोर्ड शॉर्टकट को पसंद के मुताबिक बनाएं"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"शॉर्टकट असाइन करने के लिए बटन दबाएं"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"शॉर्टकट खोजें"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"खोज का कोई नतीजा नहीं मिला"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"छोटा करने का आइकॉन"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"खींचकर छोड़ने वाला हैंडल"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"कीबोर्ड सेटिंग"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"शॉर्टकट सेट करें"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"रद्द करें"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"बटन दबाएं"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"बटन का यह कॉम्बिनेशन पहले से इस्तेमाल किया जा रहा है. कोई दूसरा कॉम्बिनेशन आज़माएं."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"कीबोर्ड का इस्तेमाल करके नेविगेट करें"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"कीबोर्ड शॉर्टकट के बारे में जानें"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"टचपैड का इस्तेमाल करके नेविगेट करें"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index a17964992..ef5cf73 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgeti na zaključanom zaslonu"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Da biste otvorili aplikaciju pomoću widgeta, trebate potvrditi da ste to vi. Također napominjemo da ih svatko može vidjeti, čak i ako je vaš tablet zaključan. Neki widgeti možda nisu namijenjeni za zaključani zaslon, pa ih možda nije sigurno dodati ovdje."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Shvaćam"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Promjena korisnika"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući izbornik"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Izbrisat će se sve aplikacije i podaci u ovoj sesiji."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikazuje se pri vrhu obavijesti razgovora i kao profilna slika na zaključanom zaslonu, izgleda kao oblačić, prekida Ne uznemiravaj"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritetno"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava značajke razgovora"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Te se obavijesti ne mogu izmijeniti."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Obavijesti o pozivima ne mogu se izmijeniti."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ta se grupa obavijesti ne može konfigurirati ovdje"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Za višu razlučivost okrenite telefon"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Rasklopljen sklopivi uređaj"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Okretanje sklopivog uređaja sa svih strana"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Prednji zaslon je uključen"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zatvoreno"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"otvoreno"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Pristupačnost"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Tipkovni prečaci"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prilagodba tipkovnih prečaca"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Pritisnite tipku da biste dodijelili prečac"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečaci za pretraživanje"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nema rezultata pretraživanja"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za sažimanje"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Marker za povlačenje"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Postavke tipkovnice"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Postavite prečac"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Odustani"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pritisnite tipku"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Kombinacija tipki već se upotrebljava. Pokušajte s drugom tipkom."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Krećite se pomoću tipkovnice"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Saznajte više o tipkovnim prečacima"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Krećite se pomoću dodirne podloge"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 4b5b916..350dc4f 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"A lezárási képernyő moduljai"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Ha modul használatával szeretne megnyitni egy alkalmazást, igazolnia kell a személyazonosságát. Ne felejtse továbbá, hogy bárki megtekintheti a modulokat, még akkor is, amikor zárolva van a táblagép. Előfordulhat, hogy bizonyos modulokat nem a lezárási képernyőn való használatra terveztek, ezért nem biztonságos a hozzáadásuk."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Értem"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Felhasználóváltás"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"lehúzható menü"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"A munkamenetben található összes alkalmazás és adat törlődni fog."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"A beszélgetésekre vonatkozó értesítések tetején, lebegő buborékként látható, megjeleníti a profilképet a lezárási képernyőn, és megszakítja a Ne zavarjanak funkciót"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritás"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> nem támogatja a beszélgetési funkciókat"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ezeket az értesítéseket nem lehet módosítani."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"A hívásértesítéseket nem lehet módosítani."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Az értesítések jelen csoportját itt nem lehet beállítani"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"A nagyobb felbontás érdekében fordítsa meg a telefont"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Összehajtható eszköz kihajtása"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Összehajtható eszköz körbeforgatása"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Előlapi képernyő bekapcsolva"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"összehajtva"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kihajtva"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Kisegítő lehetőségek"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Billentyűparancsok"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"A billentyűparancsok személyre szabása"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Nyomja meg a billentyűt a parancsikon hozzárendeléséhez"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Billentyűparancsok keresése"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nincsenek keresési találatok"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Összecsukás ikon"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Fogópont"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Billentyűzetbeállítások"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Billentyűparancs beállítása"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Mégse"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Nyomja le a billentyűt"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"A billentyűkombináció már használatban van. Próbálkozzon másik kulccsal."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigáció a billentyűzet segítségével"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Billentyűparancsok megismerése"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigálás az érintőpaddal"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index a062098..9c83301 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Կողպէկրանի վիջեթներ"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Վիջեթի միջոցով հավելված բացելու համար դուք պետք է հաստատեք ձեր ինքնությունը։ Նաև նկատի ունեցեք, որ ցանկացած ոք կարող է դիտել վիջեթները, նույնիսկ երբ ձեր պլանշետը կողպված է։ Որոշ վիջեթներ կարող են նախատեսված չլինել ձեր կողպէկրանի համար, և այստեղ դրանց ավելացնելը կարող է վտանգավոր լինել։"</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Եղավ"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Անջատել օգտվողին"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"իջնող ընտրացանկ"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Այս աշխատաշրջանի բոլոր հավելվածներն ու տվյալները կջնջվեն:"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Ցուցադրվում է զրույցների ծանուցումների վերևում, ինչպես նաև կողպէկրանին որպես պրոֆիլի նկար, հայտնվում է ամպիկի տեսքով, ընդհատում է «Չանհանգստացնել» ռեժիմը"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Կարևոր"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը զրույցի գործառույթներ չի աջակցում"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Այս ծանուցումները չեն կարող փոփոխվել:"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Զանգերի մասին ծանուցումները հնարավոր չէ փոփոխել։"</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ծանուցումների տվյալ խումբը հնարավոր չէ կարգավորել այստեղ"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Օգտագործեք մինչև <xliff:g id="LENGTH">%1$d</xliff:g> նիշ"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Կառուցման համարը"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Կառուցման համարը պատճենվեց սեղմատախտակին։"</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"պատճենել սեղմատախտակին։"</string>
     <string name="basic_status" msgid="2315371112182658176">"Բաց զրույց"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Զրույցի վիջեթներ"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Հպեք զրույցին՝ այն հիմնական էկրանին ավելացնելու համար"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Ավելի մեծ լուծաչափի համար շրջեք հեռախոսը"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Ծալովի սարք՝ բացված վիճակում"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Ծալովի սարք՝ շրջված վիճակում"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Առջևի էկրանը միացված է"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ծալված"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"բացված"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Հատուկ գործառույթներ"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Ստեղնային դյուրանցումներ"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Կարգավորեք ստեղնային դյուրանցումներ"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Սեղմեք որևէ ստեղն՝ դյուրանցում նշանակելու համար"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Դյուրանցումների որոնում"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Որոնման արդյունքներ չկան"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ծալել պատկերակը"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Տեղափոխման նշիչ"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Ստեղնաշարի կարգավորումներ"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Ստեղծել դյուրանցում"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Չեղարկել"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Սեղմեք որևէ ստեղն"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Ստեղների համակցությունն արդեն օգտագործվում է։ Ընտրեք այլ ստեղն։"</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Կողմնորոշվեք ձեր ստեղնաշարի օգնությամբ"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Սովորեք օգտագործել ստեղնային դյուրանցումները"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Կողմնորոշվեք ձեր հպահարթակի օգնությամբ"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index cf9b093..5800987 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widget layar kunci"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Untuk membuka aplikasi menggunakan widget, Anda perlu memverifikasi diri Anda. Selain itu, harap ingat bahwa siapa saja dapat melihatnya, bahkan saat tablet Anda terkunci. Beberapa widget mungkin tidak dirancang untuk layar kunci Anda dan mungkin tidak aman untuk ditambahkan di sini."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Oke"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Beralih pengguna"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu pulldown"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua aplikasi dan data dalam sesi ini akan dihapus."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Muncul teratas di notifikasi percakapan dan sebagai foto profil di layar kunci, ditampilkan sebagai balon, menimpa mode Jangan Ganggu"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritas"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak mendukung fitur percakapan"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Notifikasi ini tidak dapat diubah."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Notifikasi panggilan tidak dapat diubah."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Grup notifikasi ini tidak dapat dikonfigurasi di sini"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Untuk resolusi lebih tinggi, balik ponsel"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Perangkat foldable sedang dibentangkan"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Perangkat foldable sedang dibalik"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Layar depan diaktifkan"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ditutup"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"dibuka"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Aksesibilitas"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Pintasan keyboard"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Menyesuaikan pintasan keyboard"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Tekan tombol untuk menetapkan pintasan"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Telusuri pintasan"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Tidak ada hasil penelusuran"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikon ciutkan"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Handel geser"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Setelan Keyboard"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Setel pintasan"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Batal"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tekan tombol"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Kombinasi tombol sudah digunakan. Coba tombol lain."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Menggunakan keyboard untuk navigasi"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Pelajari pintasan keyboard"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Menavigasi menggunakan touchpad"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index fe32aba..3a36590 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Græjur fyrir lásskjá"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Þú þarft að staðfesta að þetta sért þú til að geta opnað forrit með græju. Hafðu einnig í huga að hver sem er getur skoðað þær, jafnvel þótt spjaldtölvan sé læst. Sumar græjur eru hugsanlega ekki ætlaðar fyrir lásskjá og því gæti verið óöruggt að bæta þeim við hér."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ég skil"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skipta um notanda"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"Fellivalmynd"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Öllum forritum og gögnum í þessari lotu verður eytt."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Birtist efst í samtalstilkynningum og sem prófílmynd á lásskjánum. Birtist sem blaðra sem truflar „Ónáðið ekki“"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Forgangur"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> styður ekki samtalseiginleika"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ekki er hægt að breyta þessum tilkynningum."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Ekki er hægt að breyta tilkynningum um símtöl."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ekki er hægt að stilla þessar tilkynningar hér"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Snúðu símanum til að fá betri upplausn"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Samanbrjótanlegt tæki opnað"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Samanbrjótanlegu tæki snúið við"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Kveikt á fremri skjá"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"samanbrotið"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"opið"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Aðgengi"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Flýtilyklar"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Sérsníddu flýtilykla"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Ýttu á lykil til að stilla flýtileið"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Leita að flýtileiðum"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Engar leitarniðurstöður"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Minnka tákn"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Dragkló"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Stillingar lyklaborðs"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Stilltu flýtileið"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Hætta við"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Ýttu á lykil"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Lyklasamsetning er þegar í notkun. Prófaðu annan lykil."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Flettu með því að nota lyklaborðið"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Kynntu þér flýtilykla"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Flettu með því að nota snertiflötinn"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index a66ea91..12a01eb 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -167,7 +167,7 @@
     <string name="issuerecord_start_error" msgid="3402782952722871190">"Impossibile avviare la registrazione del problema"</string>
     <string name="immersive_cling_title" msgid="8372056499315585941">"Visualizzazione a schermo intero"</string>
     <string name="immersive_cling_description" msgid="2717426731830851921">"Per uscire, scorri verso il basso dalla parte superiore dello schermo"</string>
-    <string name="immersive_cling_positive" msgid="3076681691468978568">"OK"</string>
+    <string name="immersive_cling_positive" msgid="3076681691468978568">"Ok"</string>
     <string name="accessibility_back" msgid="6530104400086152611">"Indietro"</string>
     <string name="accessibility_home" msgid="5430449841237966217">"Home"</string>
     <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string>
@@ -528,6 +528,8 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widget della schermata di blocco"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Per aprire un\'app utilizzando un widget, dovrai verificare la tua identità. Inoltre tieni presente che chiunque può vederlo, anche quando il tablet è bloccato. Alcuni widget potrebbero non essere stati progettati per la schermata di blocco e potrebbe non essere sicuro aggiungerli qui."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ok"</string>
+    <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widget"</string>
+    <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="511359420883794513">"Per aggiungere Widget alla schermata di blocco come scorciatoia, assicurati che sia abilitata nelle impostazioni."</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambio utente"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu a discesa"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tutte le app e i dati di questa sessione verranno eliminati."</string>
@@ -668,7 +670,7 @@
     <string name="screen_pinning_toast" msgid="8177286912533744328">"Per sbloccare questa app, tocca e tieni premuti i pulsanti Indietro e Panoramica"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Per sbloccare questa app, tocca e tieni premuti i pulsanti Indietro e Home"</string>
     <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Per sbloccare questa app, scorri verso l\'alto e tieni premuto"</string>
-    <string name="screen_pinning_positive" msgid="3285785989665266984">"OK"</string>
+    <string name="screen_pinning_positive" msgid="3285785989665266984">"Ok"</string>
     <string name="screen_pinning_negative" msgid="6882816864569211666">"No, grazie"</string>
     <string name="screen_pinning_start" msgid="7483998671383371313">"App bloccata"</string>
     <string name="screen_pinning_exit" msgid="4553787518387346893">"App sbloccata"</string>
@@ -751,7 +753,7 @@
     <string name="tuner_warning_title" msgid="7721976098452135267">"Il divertimento riservato a pochi eletti"</string>
     <string name="tuner_warning" msgid="1861736288458481650">"L\'Ottimizzatore UI di sistema mette a disposizione altri metodi per modificare e personalizzare l\'interfaccia utente di Android. Queste funzioni sperimentali potrebbero cambiare, interrompersi o scomparire nelle versioni successive. Procedi con cautela."</string>
     <string name="tuner_persistent_warning" msgid="230466285569307806">"Queste funzioni sperimentali potrebbero cambiare, interrompersi o scomparire nelle versioni successive. Procedi con cautela."</string>
-    <string name="got_it" msgid="477119182261892069">"OK"</string>
+    <string name="got_it" msgid="477119182261892069">"Ok"</string>
     <string name="tuner_toast" msgid="3812684836514766951">"Complimenti! L\'Ottimizzatore UI di sistema è stato aggiunto alle impostazioni."</string>
     <string name="remove_from_settings" msgid="633775561782209994">"Rimuovi dalle impostazioni"</string>
     <string name="remove_from_settings_prompt" msgid="551565437265615426">"Vuoi rimuovere l\'Ottimizzatore UI di sistema dalle impostazioni e smettere di utilizzare tutte le sue funzioni?"</string>
@@ -780,6 +782,7 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Appare in cima alle notifiche delle conversazioni, come immagine del profilo nella schermata di blocco e sotto forma di bolla, inoltre interrompe la modalità Non disturbare"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Priorità"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> non supporta le funzionalità delle conversazioni"</string>
+    <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Fornisci feedback sul bundle"</string>
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossibile modificare queste notifiche."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Impossibile modificare gli avvisi di chiamata."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Qui non è possibile configurare questo gruppo di notifiche"</string>
@@ -1357,8 +1360,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Gira il telefono per una maggiore risoluzione"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo pieghevole che viene aperto"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo pieghevole che viene capovolto"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Schermo frontale attivato"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"Piegato"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"Non piegato"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1420,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibilità"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Scorciatoie da tastiera"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizza scorciatoie da tastiera"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Premi un tasto per assegnare una scorciatoia"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Scorciatoie per la ricerca"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nessun risultato di ricerca"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icona Comprimi"</string>
@@ -1431,15 +1438,20 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Punto di trascinamento"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Impostazioni tastiera"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Imposta scorciatoia"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Annulla"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Premi un tasto"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Combinazione di tasti già in uso. Prova con un altro tasto."</string>
+    <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Combinazione di tasti già in uso. Prova con un altro tasto."</string>
+    <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Impossibile impostare la scorciatoia."</string>
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviga usando la tastiera"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Informazioni sulle scorciatoie da tastiera"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviga usando il touchpad"</string>
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Impara i gesti con il touchpad"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Naviga usando la tastiera e il touchpad"</string>
-    <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Scopri gesti con il touchpad, scorciatoie da tastiera e altro ancora"</string>
+    <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Impara i gesti con il touchpad, le scorciatoie da tastiera e altro ancora"</string>
     <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Indietro"</string>
     <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Vai alla schermata Home"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Visualizza app recenti"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 7b4245e..0a14717 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -310,7 +310,7 @@
     <string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"נשמר"</string>
     <string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ניתוק"</string>
     <string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"הפעלה"</string>
-    <string name="turn_on_bluetooth_auto_tomorrow" msgid="3345758139235739006">"הפעלה אוטומטית מחר"</string>
+    <string name="turn_on_bluetooth_auto_tomorrow" msgid="3345758139235739006">"הפעלה אוטומטית ביום הבא"</string>
     <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"‏תכונות כמו \'שיתוף מהיר\' ו\'איפה המכשיר שלי\' משתמשות ב-Bluetooth"</string>
     <string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"‏חיבור ה-Bluetooth יופעל מחר בבוקר"</string>
     <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"שיתוף האודיו"</string>
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ווידג\'טים במסך הנעילה"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"כדי לפתוח אפליקציה באמצעות ווידג\'ט, עליך לאמת את זהותך. בנוסף, כדאי לזכור שכל אחד יכול לראות את הווידג\'טים גם כשהטאבלט שלך נעול. יכול להיות שחלק מהווידג\'טים לא נועדו למסך הנעילה ושלא בטוח להוסיף אותם לכאן."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"הבנתי"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"החלפת משתמש"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"תפריט במשיכה למטה"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"כל האפליקציות והנתונים בסשן הזה יימחקו."</string>
@@ -699,7 +703,7 @@
     <string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"אודיו מרחבי"</string>
     <string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"השבתה"</string>
     <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"מצב סטטי"</string>
-    <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"מעקב אחר תנועות הראש"</string>
+    <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"מעקב ראש"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"יש להקיש כדי לשנות את מצב תוכנת הצלצול"</string>
     <string name="volume_ringer_mode" msgid="6867838048430807128">"מצב תוכנת הצלצול"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"השתקה"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"מוצגת בחלק העליון של קטע התראות השיחה וכתמונת פרופיל במסך הנעילה, מופיעה בבועה צפה ומפריעה במצב \'נא לא להפריע\'"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"בעדיפות גבוהה"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא תומכת בתכונות השיחה"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"לא ניתן לשנות את ההתראות האלה."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"לא ניתן לשנות את התראות השיחה."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"לא ניתן להגדיר כאן את קבוצת ההתראות הזו"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"כדי לצלם תמונה ברזולוציה גבוהה יותר, כדאי להפוך את הטלפון"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"מכשיר מתקפל עובר למצב לא מקופל"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"מכשיר מתקפל עובר למצב מהופך"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"המסך הקדמי מופעל"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"מצב מקופל"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"מצב לא מקופל"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"‏%1$s‏ / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"נגישות"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"מקשי קיצור"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"התאמה אישית של מקשי הקיצור"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"יש ללחוץ על מקש כדי להקצות מקש קיצור"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"קיצורי דרך לחיפוש"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"אין תוצאות חיפוש"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"סמל הכיווץ"</string>
@@ -1431,15 +1441,22 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"נקודת האחיזה לגרירה"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"הגדרות המקלדת"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"הגדרה של מקש קיצור"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ביטול"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"יש ללחוץ על מקש"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"שילוב המקשים הזה כבר בשימוש. אפשר לנסות מקש אחר."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ניווט באמצעות המקלדת"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"מידע על מקשי קיצור"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ניווט באמצעות לוח המגע"</string>
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"מידע על התנועות בלוח המגע"</string>
-    <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"ניווט באמצעות המקלדת ולוח המגע"</string>
-    <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"מידע על התנועות בלוח המגע, מקשי קיצור ועוד"</string>
+    <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"ניווט עם המקלדת ולוח המגע"</string>
+    <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"כאן אפשר לקרוא איך מפעילים תנועות בלוח המגע, מקשי קיצור ועוד"</string>
     <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"חזרה"</string>
     <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"חזרה לדף הבית"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"הצגת האפליקציות האחרונות"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index c4fd62b..1c106cf 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ロック画面ウィジェット"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ウィジェットを使用してアプリを起動するには、本人確認が必要です。タブレットがロックされた状態でも他のユーザーにウィジェットが表示されますので、注意してください。一部のウィジェットについてはロック画面での使用を想定していないため、ロック画面への追加は危険な場合があります。"</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ユーザーを切り替える"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"プルダウン メニュー"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"このセッションでのアプリとデータはすべて削除されます。"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"会話通知の一番上に表示されると同時に、ロック画面にプロフィール写真として表示されるほか、バブルとして表示され、サイレント モードが中断されます"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"優先"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>は会話機能に対応していません"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"これらの通知は変更できません。"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"着信通知は変更できません。"</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"このグループの通知はここでは設定できません"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"使用できる文字数は <xliff:g id="LENGTH">%1$d</xliff:g> 文字未満です"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"ビルド番号"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"ビルド番号をクリップボードにコピーしました。"</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"クリップボードにコピー。"</string>
     <string name="basic_status" msgid="2315371112182658176">"空の会話"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"会話ウィジェット"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"会話をタップするとホーム画面に追加されます"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"高解像度で撮るにはスマートフォンを裏返してください"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"折りたたみ式デバイスが広げられている"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"折りたたみ式デバイスがひっくり返されている"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"フロント画面が ON になりました"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"折りたたんだ状態"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"広げた状態"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ユーザー補助"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"キーボード ショートカット"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"キーボード ショートカットをカスタマイズする"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"ショートカットを割り当てるキーを押してください"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"検索ショートカット"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"検索結果がありません"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"閉じるアイコン"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ドラッグ ハンドル"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"キーボードの設定"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ショートカットの設定"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"キャンセル"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"キーを押してください"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"このキーの組み合わせはすでに使用されています。別のキーを試してください。"</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"キーボードを使用して移動する"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"キーボード ショートカットの詳細"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"タッチパッドを使用して移動する"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 7cb3c8a..962a62c 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"დაბლოკილი ეკრანის ვიჯეტები"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"უნდა დაადასტუროთ თქვენი ვინაობა, რათა გახსნათ აპი ვიჯეტის გამოყენებით. გაითვალისწინეთ, რომ ნებისმიერს შეუძლია მათი ნახვა, მაშინაც კი, როცა ტაბლეტი დაბლოკილია. ზოგი ვიჯეტი შეიძლება არ იყოს გათვლილი თქვენი დაბლოკილი ეკრანისთვის და მათი აქ დამატება შეიძლება სახიფათო იყოს."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"გასაგებია"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"მომხმარებლის გადართვა"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ჩამოშლადი მენიუ"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ამ სესიის ყველა აპი და მონაცემი წაიშლება."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"გამოჩნდება საუბრის შეტყობინებების თავში და პროფილის სურათის სახით ჩაკეტილ ეკრანზე, ჩნდება ბუშტის სახით, წყვეტს ფუნქციას „არ შემაწუხოთ“"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"პრიორიტეტი"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ს არ აქვს მიმოწერის ფუნქციების მხარდაჭერა"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"ამ შეტყობინებების შეცვლა შეუძლებელია."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"ზარის შეტყობინებების შეცვლა შეუძლებელია."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"შეტყობინებების ამ ჯგუფის კონფიგურირება აქ შეუძლებელია"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"მაღალი გარჩევადობისთვის ამოაბრუნეთ ტელეფონი"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"დასაკეცი მოწყობილობა იხსნება"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"დასაკეცი მოწყობილობა ტრიალებს"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"წინა ეკრანი ჩართულია"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"დაკეცილი"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"გაშლილი"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"მისაწვდომობა"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"კლავიატურის მალსახმობები"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"კლავიატურის მალსახმობების მორგება"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"მალსახმობის მინიჭებისთვის დააჭირეთ კლავიშს"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ძიების მალსახმობები"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ძიების შედეგები არ არის"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ხატულის ჩაკეცვა"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"სახელური ჩავლებისთვის"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"კლავიატურის პარამეტრები"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"მალსახმობის დაყენება"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"გაუქმება"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"დააჭირეთ კლავიშს"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"კლავიშების კომბინაცია უკვე გამოიყენება. ცადეთ სხვა კლავიში."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ნავიგაცია კლავიატურის გამოყენებით"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"კლავიატურის მალსახმობების სწავლა"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ნავიგაცია სენსორული პანელის გამოყენებით"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 4122eee..ec1f096 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Құлып экранының виджеттері"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Қолданбаны виджет көмегімен ашу үшін жеке басыңызды растауыңыз керек. Сондай-ақ басқалар оларды планшетіңіз құлыптаулы кезде де көре алатынын ескеріңіз. Кейбір виджеттер құлып экранына арналмаған болады, сондықтан оларды мұнда қосу қауіпсіз болмауы мүмкін."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Түсінікті"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Пайдаланушыны ауыстыру"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ашылмалы мәзір"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Осы сеанстағы барлық қолданба мен дерек жойылады."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Әңгіме туралы хабарландырулардың жоғарғы жағында тұрады және құлыптаулы экранда профиль суреті болып көрсетіледі, қалқыма хабар түрінде шығады, Мазаламау режимін тоқтатады."</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Маңызды"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> әңгіме функцияларын қолдамайды."</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Бұл хабарландыруларды өзгерту мүмкін емес."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Қоңырау туралы хабарландыруларды өзгерту мүмкін емес."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Мұндай хабарландырулар бұл жерде конфигурацияланбайды."</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Жоғары ажыратымдылық үшін телефонды айналдырыңыз."</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Бүктемелі құрылғы ашылып жатыр."</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Бүктемелі құрылғы аударылып жатыр."</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Алдыңғы экран қосылды."</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"жабық"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ашық"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Арнайы мүмкіндіктер"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Перне тіркесімдері"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Пернелер тіркесімін бейімдеу"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Жылдам пәрменді тағайындау үшін пернені басыңыз."</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Іздеу жылдам пәрмендері"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Іздеу нәтижелері жоқ."</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Жию белгішесі"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Сүйрейтін тетік"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Пернетақта параметрлері"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Жылдам пәрменді орнату"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Бас тарту"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Пернені басыңыз"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Бұл пернелер тіркесімі қазір қолданыста. Басқа пернені таңдаңыз."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Пернетақтамен жұмыс істеңіз"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Перне тіркесімдерін үйреніңіз."</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Сенсорлық тақтамен жұмыс істеңіз"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index f9ec58f..2533f98 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ធាតុ​ក្រាហ្វិកលើអេក្រង់ចាក់សោ"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ដើម្បីបើកកម្មវិធីដោយប្រើធាតុ​ក្រាហ្វិក អ្នកនឹងត្រូវផ្ទៀងផ្ទាត់ថាជាអ្នក។ ទន្ទឹមនឹងនេះ សូមចងចាំថា នរណាក៏អាចមើលធាតុក្រាហ្វិកបាន សូម្បីពេលថេប្លេតរបស់អ្នកជាប់សោក៏ដោយ។ ធាតុ​ក្រាហ្វិកមួយចំនួនប្រហែលមិនត្រូវបានរចនាឡើងសម្រាប់អេក្រង់ចាក់សោរបស់អ្នកទេ និងមិនមានសុវត្ថិភាពឡើយ បើបញ្ចូលទៅទីនេះ។"</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"យល់ហើយ"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ប្ដូរ​អ្នក​ប្រើ"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ម៉ឺនុយ​ទាញចុះ"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"កម្មវិធី និងទិន្នន័យ​ទាំងអស់​ក្នុង​វគ្គ​នេះ​នឹង​ត្រូវ​លុប។"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"បង្ហាញនៅខាងលើ​ការជូនដំណឹងអំពីការសន្ទនា និងជារូបភាព​កម្រង​ព័ត៌មាននៅលើអេក្រង់ចាក់សោ បង្ហាញជាពពុះ បង្អាក់មុខងារកុំ​រំខាន"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"អាទិភាព"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនអាចប្រើ​មុខងារ​សន្ទនា​បានទេ"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"មិនអាច​កែប្រែ​ការជូនដំណឹង​ទាំងនេះ​បានទេ។"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"មិនអាច​កែប្រែ​ការជូនដំណឹងអំពីការហៅទូរសព្ទបានទេ។"</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"មិនអាច​កំណត់​រចនាសម្ព័ន្ធ​ក្រុមការជូនដំណឹងនេះ​នៅទីនេះ​បានទេ"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"សម្រាប់កម្រិតគុណភាពកាន់តែខ្ពស់ សូមត្រឡប់ទូរសព្ទ"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ឧបករណ៍អាច​បត់បានកំពុងត្រូវបានលា"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ឧបករណ៍អាច​បត់បានកំពុងត្រូវបានលា"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"បានបើកអេក្រង់ខាងមុខ"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"បត់"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"លា"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ភាពងាយស្រួល"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"ផ្លូវកាត់​ក្ដារ​ចុច"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"ប្ដូរ​ផ្លូវកាត់​ក្ដារ​ចុចតាម​បំណង"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"ចុចគ្រាប់ចុច ដើម្បីកំណត់ផ្លូវ​កាត់"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ស្វែងរកផ្លូវ​កាត់"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"គ្មាន​លទ្ធផល​ស្វែងរក​ទេ"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"រូបតំណាង \"បង្រួម\""</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ដង​អូស"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"ការកំណត់​ក្ដារចុច"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"កំណត់ផ្លូវ​កាត់"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"បោះបង់"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ចុចគ្រាប់ចុច"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"កំពុងប្រើបន្សំគ្រាប់ចុចស្រាប់ហើយ។ សាកល្បងប្រើគ្រាប់ចុចផ្សេង។"</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"រុករកដោយប្រើក្ដារចុចរបស់អ្នក"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ស្វែងយល់អំពីផ្លូវកាត់​ក្ដារ​ចុច"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"រុករកដោយប្រើផ្ទាំងប៉ះរបស់អ្នក"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index f315570..201c995 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ಲಾಕ್ ಸ್ಕ್ರೀನ್ ವಿಜೆಟ್‌ಗಳು"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ವಿಜೆಟ್ ಅನ್ನು ಬಳಸಿಕೊಂಡು ಆ್ಯಪ್ ತೆರೆಯಲು, ಇದು ನೀವೇ ಎಂದು ನೀವು ದೃಢೀಕರಿಸಬೇಕಾಗುತ್ತದೆ. ಅಲ್ಲದೆ, ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಲಾಕ್ ಆಗಿದ್ದರೂ ಸಹ ಯಾರಾದರೂ ಅವುಗಳನ್ನು ವೀಕ್ಷಿಸಬಹುದು ಎಂಬುದನ್ನು ನೆನಪಿನಲ್ಲಿಡಿ. ಕೆಲವು ವಿಜೆಟ್‌ಗಳು ನಿಮ್ಮ ಲಾಕ್ ಸ್ಕ್ರೀನ್‌ಗಾಗಿ ಉದ್ದೇಶಿಸದೇ ಇರಬಹುದು ಮತ್ತು ಇಲ್ಲಿ ಸೇರಿಸುವುದು ಸುರಕ್ಷಿತವಲ್ಲದಿರಬಹುದು."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ಅರ್ಥವಾಯಿತು"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ಬಳಕೆದಾರರನ್ನು ಬದಲಿಸಿ"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ಪುಲ್‌ಡೌನ್ ಮೆನು"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ಈ ಸೆಶನ್‌ನಲ್ಲಿನ ಎಲ್ಲಾ ಆ್ಯಪ್‌ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"ಸಂಭಾಷಣೆ ಅಧಿಸೂಚನೆಗಳ ಮೇಲ್ಭಾಗದಲ್ಲಿ ಹಾಗೂ ಲಾಕ್ ಸ್ಕ್ರೀನ್‌ನ ಮೇಲೆ ಪ್ರೊಫೈಲ್ ಚಿತ್ರವಾಗಿ ತೋರಿಸುತ್ತದೆ, ಬಬಲ್‌ನಂತೆ ಗೋಚರಿಸುತ್ತದೆ, ಅಡಚಣೆ ಮಾಡಬೇಡ ಮೋಡ್‌ಗೆ ಅಡ್ಡಿಯುಂಟುಮಾಡುತ್ತದೆ"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"ಆದ್ಯತೆ"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"ಸಂವಾದ ಫೀಚರ್‌ಗಳನ್ನು <xliff:g id="APP_NAME">%1$s</xliff:g> ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"ಕರೆ ಅಧಿಸೂಚನೆಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"ಈ ಗುಂಪಿನ ಅಧಿಸೂಚನೆಗಳನ್ನು ಇಲ್ಲಿ ಕಾನ್ಫಿಗರ್‌ ಮಾಡಲಾಗಿರುವುದಿಲ್ಲ"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"ಅಧಿಕ ರೆಸಲ್ಯೂಷನ್‌ಗಾಗಿ, ಫೋನ್ ಅನ್ನು ಫ್ಲಿಪ್ ಮಾಡಿ"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ಫೋಲ್ಡ್ ಮಾಡಬಹುದಾದ ಸಾಧನವನ್ನು ಅನ್‌ಫೋಲ್ಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ಫೋಲ್ಡ್ ಮಾಡಬಹುದಾದ ಸಾಧನವನ್ನು ಸುತ್ತಲೂ ತಿರುಗಿಸಲಾಗುತ್ತಿದೆ"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ಫ್ರಂಟ್ ಸ್ಕ್ರೀನ್ ಆನ್ ಆಗಿದೆ"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ಫೋಲ್ಡ್ ಮಾಡಿರುವುದು"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ಅನ್‌ಫೋಲ್ಡ್ ಮಾಡಿರುವುದು"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"ಶಾರ್ಟ್‌ಕಟ್ ಅನ್ನು ನಿಯೋಜಿಸಲು ಕೀಯನ್ನು ಒತ್ತಿರಿ"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ಹುಡುಕಾಟದ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ಯಾವುದೇ ಹುಡುಕಾಟ ಫಲಿತಾಂಶಗಳಿಲ್ಲ"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ಕುಗ್ಗಿಸುವ ಐಕಾನ್"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ಡ್ರ್ಯಾಗ್‌ ಹ್ಯಾಂಡಲ್‌"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"ಕೀಬೋರ್ಡ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ಶಾರ್ಟ್‌ಕಟ್ ಸೆಟ್ ಮಾಡಿ"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ರದ್ದುಮಾಡಿ"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ಕೀ ಅನ್ನು ಒತ್ತಿರಿ"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"ಕೀ ಸಂಯೋಜನೆಯು ಈಗಾಗಲೇ ಬಳಕೆಯಲ್ಲಿದೆ. ಮತ್ತೊಂದು ಕೀ ಬಳಸಿ ನೋಡಿ."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ ಬಳಸಿ ನ್ಯಾವಿಗೇಟ್ ಮಾಡಿ"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಕಲಿಯಿರಿ"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ನಿಮ್ಮ ಟಚ್‌ಪ್ಯಾಡ್ ಬಳಸಿ ನ್ಯಾವಿಗೇಟ್ ಮಾಡಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 931066b..3303932 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"잠금 화면 위젯"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"위젯을 사용하여 앱을 열려면 본인 인증을 해야 합니다. 또한 태블릿이 잠겨 있더라도 누구나 볼 수 있다는 점을 유의해야 합니다. 일부 위젯은 잠금 화면에 적합하지 않고 여기에 추가하기에 안전하지 않을 수 있습니다."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"확인"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"사용자 전환"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"풀다운 메뉴"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"이 세션에 있는 모든 앱과 데이터가 삭제됩니다."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"대화 알림 상단에 표시, 잠금 화면에 프로필 사진으로 표시, 대화창으로 표시, 방해 금지 모드를 무시함"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"우선순위"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱은 대화 기능을 지원하지 않습니다."</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"이 알림은 수정할 수 없습니다."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"전화 알림은 수정할 수 없습니다."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"이 알림 그룹은 여기에서 설정할 수 없습니다."</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"해상도를 높이려면 후면 카메라를 사용하세요."</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"폴더블 기기를 펼치는 모습"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"폴더블 기기를 뒤집는 모습"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"전면 화면 켜짐"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"접은 상태"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"펼친 상태"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"접근성"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"단축키"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"단축키 맞춤설정"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"키를 눌러 단축키 지정"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"검색 바로가기"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"검색 결과 없음"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"접기 아이콘"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"드래그 핸들"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"키보드 설정"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"단축키 설정"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"취소"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"키를 누르세요."</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"이미 사용 중인 키 조합입니다. 다른 키를 사용해 보세요."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"키보드를 사용하여 이동"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"단축키에 관해 알아보세요."</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"터치패드를 사용하여 이동"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index fc16164..fb1b713 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Кулпуланган экрандагы виджеттер"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Колдонмону виджет аркылуу ачуу үчүн өзүңүздү ырасташыңыз керек. Алар кулпуланган планшетиңизде да көрүнүп турат. Кээ бир виджеттерди кулпуланган экранда колдоно албайсыз, андыктан аларды ал жерге кошпой эле койгонуңуз оң."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Түшүндүм"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Колдонуучуну которуу"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ылдый түшүүчү меню"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Бул сеанстагы бардык колдонмолор жана аларга байланыштуу нерселер өчүрүлөт."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Cүйлөшүүлөр тууралуу билдирмелердин жогору жагында жана кулпуланган экранда профилдин сүрөтү, ошондой эле калкып чыкма билдирме түрүндө көрүнүп, \"Тынчымды алба\" режимин токтотот"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Маанилүүлүгү"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда оозеки сүйлөшкөнгө болбойт"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Бул билдирмелерди өзгөртүүгө болбойт."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Чалуу билдирмелерин өзгөртүүгө болбойт."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Бул билдирмелердин тобун бул жерде конфигурациялоого болбойт"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Жогорку дааналык үчүн телефондун арткы камерасын колдонуңуз"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Ачылып турган бүктөлмө түзмөк"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Оодарылып жаткан бүктөлмө түзмөк"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Маңдайкы экран күйгүзүлдү"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"бүктөлгөн"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ачылган"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Атайын мүмкүнчүлүктөр"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Ыкчам баскычтар"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Ыкчам баскычтарды ыңгайлаштыруу"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Ыкчам баскычты дайындоо үчүн баскычты басыңыз"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Ыкчам баскычтарды издөө"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Эч нерсе табылган жок"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Жыйыштыруу сүрөтчөсү"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Cүйрөө маркери"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Баскычтоп параметрлери"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Ыкчам баскычты тууралоо"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Баскычты басыңыз"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Ачкыч айкалышы колдонулууда. Башка ачкычты байкап көрүңүз."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Керектүү нерселерге баскычтоп аркылуу өтүү"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Ыкчам баскычтар тууралуу билип алыңыз"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Керектүү жерге сенсордук такта аркылуу өтөсүз"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 3a8c682..d2e4763 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ວິດເຈັດໃນໜ້າຈໍລັອກ"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ເພື່ອເປີດແອັບໂດຍໃຊ້ວິດເຈັດ, ທ່ານຈະຕ້ອງຢັ້ງຢືນວ່າແມ່ນທ່ານ. ນອກຈາກນັ້ນ, ກະລຸນາຮັບຊາບວ່າທຸກຄົນສາມາດເບິ່ງຂໍ້ມູນດັ່ງກ່າວໄດ້, ເຖິງແມ່ນວ່າແທັບເລັດຂອງທ່ານຈະລັອກຢູ່ກໍຕາມ. ວິດເຈັດບາງຢ່າງອາດບໍ່ໄດ້ມີໄວ້ສຳລັບໜ້າຈໍລັອກຂອງທ່ານ ແລະ ອາດບໍ່ປອດໄພທີ່ຈະເພີ່ມໃສ່ບ່ອນນີ້."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ເຂົ້າໃຈແລ້ວ"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ສະຫຼັບຜູ້ໃຊ້"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ເມນູແບບດຶງລົງ"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ແອັບຯ​ແລະ​ຂໍ້​ມູນ​ທັງ​ໝົດ​ໃນ​ເຊດ​ຊັນ​ນີ້​ຈະ​ຖືກ​ລຶບ​ອອກ."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"ສະແດງຢູ່ເທິງສຸດຂອງການແຈ້ງເຕືອນການສົນທະນາ ແລະ ເປັນຮູບໂປຣໄຟລ໌ຢູ່ໜ້າຈໍລັອກ, ປາກົດເປັນຟອງ, ສະແດງໃນໂໝດຫ້າມລົບກວນໄດ້"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"ສຳຄັນ"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ຮອງຮັບຄຸນສົມບັດການສົນທະນາ"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"ບໍ່ສາມາດແກ້ໄຂການແຈ້ງເຕືອນເຫຼົ່ານີ້ໄດ້."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"ບໍ່ສາມາດແກ້ໄຂການແຈ້ງເຕືອນການໂທໄດ້."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"ບໍ່ສາມາດຕັ້ງຄ່າກຸ່ມການແຈ້ງເຕືອນນີ້ຢູ່ບ່ອນນີ້ໄດ້"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"ໃຊ້ໜ້ອຍກວ່າ <xliff:g id="LENGTH">%1$d</xliff:g> ຕົວອັກສອນ"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"ໝາຍເລກສ້າງ"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"ສຳເນົາໝາຍເລກສ້າງໄປໃສ່ຄລິບບອດແລ້ວ."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"ສຳເນົາໄປໃສ່ຄລິບບອດ."</string>
     <string name="basic_status" msgid="2315371112182658176">"ເປີດການສົນທະນາ"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"ວິດເຈັດການສົນທະນາ"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"ແຕະໃສ່ການສົນທະນາໃດໜຶ່ງເພື່ອເພີ່ມມັນໃສ່ໂຮມສະກຣີນຂອງທ່ານ"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"ເພື່ອຄວາມລະອຽດທີ່ສູງຂຶ້ນ, ໃຫ້ປີ້ນໂທລະສັບ"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ອຸປະກອນທີ່ພັບໄດ້ກຳລັງກາງອອກ"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ອຸປະກອນທີ່ພັກໄດ້ກຳລັງປີ້ນໄປມາ"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ເປີດໜ້າຈໍດ້ານໜ້າແລ້ວ"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ພັບແລ້ວ"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ກາງອອກແລ້ວ"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ການຊ່ວຍເຂົ້າເຖິງ"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"ຄີລັດ"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"ປັບແຕ່ງຄີລັດ"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"ກົດປຸ່ມເພື່ອກໍານົດທາງລັດ"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ທາງລັດການຊອກຫາ"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ບໍ່ມີຜົນການຊອກຫາ"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ໄອຄອນຫຍໍ້ລົງ"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ບ່ອນຈັບລາກ"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"ການຕັ້ງຄ່າແປ້ນພິມ"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ຕັ້ງທາງລັດ"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ຍົກເລີກ"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ກົດປຸ່ມ"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"ນໍາໃຊ້ປຸ່ມປະສົມຢູ່ແລ້ວ. ໃຫ້ລອງປຸ່ມອື່ນ."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ນຳທາງໂດຍໃຊ້ແປ້ນພິມຂອງທ່ານ"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ສຶກສາຄີລັດ"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ນຳທາງໂດຍໃຊ້ແຜ່ນສຳຜັດຂອງທ່ານ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index ae85ed2..64f37ae 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -528,6 +528,8 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Užrakinimo ekrano valdikliai"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Kad galėtumėte atidaryti programą naudodami valdiklį, turėsite patvirtinti savo tapatybę. Be to, atminkite, kad bet kas gali peržiūrėti valdiklius net tada, kai planšetinis kompiuteris užrakintas. Kai kurie valdikliai gali būti neskirti jūsų užrakinimo ekranui ir gali būti nesaugu juos čia pridėti."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Supratau"</string>
+    <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Valdikliai"</string>
+    <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="511359420883794513">"Jei norite pridėti valdiklių šaukinį užrakinimo ekrane, įsitikinkite, kad tai įgalinta nustatymuose."</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Perjungti naudotoją"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"išplečiamasis meniu"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bus ištrintos visos šios sesijos programos ir duomenys."</string>
@@ -674,7 +676,7 @@
     <string name="screen_pinning_exit" msgid="4553787518387346893">"Programa atsegta"</string>
     <string name="stream_voice_call" msgid="7468348170702375660">"Skambutis"</string>
     <string name="stream_system" msgid="7663148785370565134">"Sistema"</string>
-    <string name="stream_ring" msgid="7550670036738697526">"Skambutis"</string>
+    <string name="stream_ring" msgid="7550670036738697526">"Skambėjimas"</string>
     <string name="stream_music" msgid="2188224742361847580">"Medija"</string>
     <string name="stream_alarm" msgid="16058075093011694">"Signalas"</string>
     <string name="stream_notification" msgid="7930294049046243939">"Pranešimas"</string>
@@ -780,6 +782,7 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Rodoma pokalbių pranešimų viršuje ir kaip profilio nuotrauka užrakinimo ekrane, burbule, pertraukia netrukdymo režimą"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritetiniai"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ nepalaiko pokalbių funkcijų"</string>
+    <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Pateikti atsiliepimą apie rinkinį"</string>
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Šių pranešimų keisti negalima."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Skambučių pranešimų keisti negalima."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Šios grupės pranešimai čia nekonfigūruojami"</string>
@@ -1357,8 +1360,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Kad raiška būtų geresnė, apverskite telefoną"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Lankstomasis įrenginys išlankstomas"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Lankstomasis įrenginys apverčiamas"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Priekinis ekranas įjungtas"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"sulenkta"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"nesulenkta"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1420,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Pritaikomumas"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Spartieji klavišai"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Sparčiųjų klavišų tinkinimas"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Paspauskite klavišą, kad priskirtumėte spartųjį klavišą"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Ieškoti sparčiųjų klavišų"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nėra jokių paieškos rezultatų"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Sutraukimo piktograma"</string>
@@ -1431,9 +1438,14 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Vilkimo rankenėlė"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Klaviatūros nustatymai"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Nustatyti spartųjį klavišą"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Atšaukti"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Paspauskite klavišą"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Klavišų derinys jau naudojamas. Bandykite naudoti kitą klavišą."</string>
+    <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Klavišų derinys jau naudojamas. Bandykite naudoti kitą klavišą."</string>
+    <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Sparčiojo klavišo nustatyti negalima."</string>
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naršykite naudodamiesi klaviatūra"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Sužinokite apie sparčiuosius klavišus"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naršykite naudodamiesi jutikline dalimi"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index b20ab36..dc1c4ba 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Bloķēšanas ekrāna logrīki"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Lai atvērtu lietotni, izmantojot logrīku, jums būs jāapstiprina sava identitāte. Turklāt ņemiet vērā, ka ikviens var skatīt logrīkus, pat ja planšetdators ir bloķēts. Iespējams, daži logrīki nav paredzēti izmantošanai bloķēšanas ekrānā, un var nebūt droši tos šeit pievienot."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Labi"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mainīt lietotāju"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"novelkamā izvēlne"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tiks dzēstas visas šīs sesijas lietotnes un dati."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Parādās sarunu paziņojumu augšdaļā un kā profila attēls bloķēšanas ekrānā, arī kā burbulis, pārtrauc režīmu “Netraucēt”."</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritārs"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"Lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g> netiek atbalstītas sarunu funkcijas."</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Šos paziņojumus nevar modificēt."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Paziņojumus par zvaniem nevar modificēt."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Šeit nevar konfigurēt šo paziņojumu grupu."</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Lai izmantotu augstāku izšķirtspēju, apvērsiet tālruni"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Salokāma ierīce tiek atlocīta"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Salokāma ierīce tiek apgriezta"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Priekšējais ekrāns ir ieslēgts"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"aizvērta"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"atvērta"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Pieejamība"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Īsinājumtaustiņi"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Īsinājumtaustiņu pielāgošana"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Lai piešķirtu īsinājumtaustiņu, nospiediet taustiņu"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Meklēt saīsnes"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nav meklēšanas rezultātu"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Sakļaušanas ikona"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Vilkšanas turis"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Tastatūras iestatījumi"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Iestatīt īsinājumtaustiņu"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Atcelt"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Nospiediet taustiņu"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Taustiņu kombinācija jau tiek izmantota. Izmēģiniet citu taustiņu."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Pārvietošanās, izmantojot tastatūru"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Uzziniet par īsinājumtaustiņiem."</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Pārvietošanās, izmantojot skārienpaliktni"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index f8bfcf9..94f295f 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Виџети на заклучен екран"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"За да отворите апликација со помош на виџет, ќе треба да потврдите дека сте вие. Покрај тоа, имајте предвид дека секој може да ги гледа виџетите, дури и кога вашиот таблет е заклучен. Некои виџети можеби не се наменети за вашиот заклучен екран, па можеби не е безбедно да се додадат овде."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Сфатив"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Промени го корисникот"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"паѓачко мени"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Сите апликации и податоци во сесијава ќе се избришат."</string>
@@ -698,7 +702,7 @@
     <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Контрола на шум"</string>
     <string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"Просторен звук"</string>
     <string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"Исклучено"</string>
-    <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Фиксно"</string>
+    <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Фиксирано"</string>
     <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Следење на главата"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Допрете за да го промените режимот на ѕвончето"</string>
     <string name="volume_ringer_mode" msgid="6867838048430807128">"режим на ѕвонче"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Се прикажува најгоре во известувањата за разговор и како профилна слика на заклучен екран, се појавува како балонче, го прекинува „Не вознемирувај“"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Приоритетно"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддржува функции за разговор"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Овие известувања не може да се изменат"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Известувањата за повици не може да се изменат."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Оваа група известувања не може да се конфигурира тука"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Отворете го телефонот за да добиете повисока резолуција"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Преклопувачки уред се отклопува"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Преклопувачки уред се врти"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Предниот екран е вклучен"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"затворен"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"отворен"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Пристапност"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Кратенки од тастатура"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Приспособете ги кратенките од тастатурата"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Притиснете го копчето за да доделите кратенка"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Пребарувајте кратенки"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Нема резултати од пребарување"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за собирање"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Рачка за влечење"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Поставки за тастатурата"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Поставете кратенка"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Откажи"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Притиснете го копчето"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Комбинацијата на копчиња веќе се користи. Обидете се со друго копче."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Движете се со користење на тастатурата"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Научете ги кратенките од тастатурата"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Движете се со користење на допирната подлога"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 54364c8..85bc701 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ലോക്ക് സ്‌ക്രീൻ വിജറ്റുകൾ"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"വിജറ്റ് ഉപയോഗിച്ച് ഒരു ആപ്പ് തുറക്കാൻ, ഇത് നിങ്ങൾ തന്നെയാണെന്ന് പരിശോധിച്ചുറപ്പിക്കേണ്ടതുണ്ട്. നിങ്ങളുടെ ടാബ്‌ലെറ്റ് ലോക്കായിരിക്കുമ്പോഴും എല്ലാവർക്കും അത് കാണാനാകുമെന്നതും ഓർക്കുക. ചില വിജറ്റുകൾ നിങ്ങളുടെ ലോക്ക് സ്‌ക്രീനിന് ഉള്ളതായിരിക്കില്ല, അവ ഇവിടെ ചേർക്കുന്നത് സുരക്ഷിതവുമായിരിക്കില്ല."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"മനസ്സിലായി"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ഉപയോക്താവ് മാറുക"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"പുൾഡൗൺ മെനു"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ഈ സെഷനിലെ എല്ലാ ആപ്പുകളും ഡാറ്റയും ഇല്ലാതാക്കും."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"സംഭാഷണ അറിയിപ്പുകളുടെ മുകളിലും സ്ക്രീൻ ലോക്കായിരിക്കുമ്പോൾ ഒരു പ്രൊഫൈൽ ചിത്രമായും ബബിൾ രൂപത്തിൽ ദൃശ്യമാകുന്നു, ശല്യപ്പെടുത്തരുത് മോഡ് തടസ്സപ്പെടുത്തുന്നു"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"മുൻഗണന"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"സംഭാഷണ ഫീച്ചറുകളെ <xliff:g id="APP_NAME">%1$s</xliff:g> പിന്തുണയ്‌ക്കുന്നില്ല"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"ഈ അറിയിപ്പുകൾ പരിഷ്ക്കരിക്കാനാവില്ല."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"കോൾ അറിയിപ്പുകൾ പരിഷ്‌കരിക്കാനാകുന്നില്ല."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"അറിയിപ്പുകളുടെ ഈ ഗ്രൂപ്പ് ഇവിടെ കോണ്‍ഫിഗര്‍ ചെയ്യാൻ കഴിയില്ല"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g>-ൽ കുറവ് പ്രതീകങ്ങൾ ഉപയോഗിക്കുക"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"ബിൽഡ് നമ്പർ"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"ക്ലിപ്പ്ബോർഡിലേക്ക് ബിൽഡ് നമ്പർ പകർത്തി."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"ക്ലിപ്പ്ബോർഡിലേക്ക് പകർത്തുക."</string>
     <string name="basic_status" msgid="2315371112182658176">"സംഭാഷണം തുറക്കുക"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"സംഭാഷണ വിജറ്റുകൾ"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"നിങ്ങളുടെ ഹോം സ്‌ക്രീനിൽ ചേർക്കാൻ സംഭാഷണത്തിൽ ടാപ്പ് ചെയ്യുക"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"ഉയർന്ന റെസല്യൂഷന്, ഫോൺ ഫ്ലിപ്പ് ചെയ്യുക"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ഫോൾഡ് ചെയ്യാവുന്ന ഉപകരണം അൺഫോൾഡ് ആകുന്നു"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ഫോൾഡ് ചെയ്യാവുന്ന ഉപകരണം, കറങ്ങുന്ന വിധത്തിൽ ഫ്ലിപ്പ് ആകുന്നു"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ഫ്രണ്ട് സ്ക്രീൻ ഓണാക്കി"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ഫോൾഡ് ചെയ്തത്"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"അൺഫോൾഡ് ചെയ്തത്"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ഉപയോഗസഹായി"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"കീബോഡ് കുറുക്കുവഴികൾ"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"കീബോർഡ് കുറുക്കുവഴികൾ ഇഷ്ടാനുസൃതമാക്കുക"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"കുറുക്കുവഴി അസൈൻ ചെയ്യാൻ കീ അമർത്തുക"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"തിരയൽ കുറുക്കുവഴികൾ"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"തിരയൽ ഫലങ്ങളൊന്നുമില്ല"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ചുരുക്കൽ ഐക്കൺ"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"വലിച്ചിടുന്നതിനുള്ള ഹാൻഡിൽ"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"കീബോർഡ് ക്രമീകരണം"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"കുറുക്കുവഴി സജ്ജീകരിക്കുക"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"റദ്ദാക്കുക"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"കീ അമർത്തുക"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"കീ കോമ്പിനേഷൻ ഇതിനകം ഉപയോഗത്തിലുണ്ട്. മറ്റൊരു കീ പരീക്ഷിക്കുക."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"നിങ്ങളുടെ കീബോർഡ് ഉപയോഗിച്ച് നാവിഗേറ്റ് ചെയ്യുക"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"കീബോർഡ് കുറുക്കുവഴികൾ മനസ്സിലാക്കുക"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"നിങ്ങളുടെ ടച്ച്‌പാഡ് ഉപയോഗിച്ച് നാവിഗേറ്റ് ചെയ്യുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 0e2dc23..78b2dda 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Түгжээтэй дэлгэцийн виджет"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Виджет ашиглан аппыг нээхийн тулд та өөрийгөө мөн болохыг баталгаажуулах шаардлагатай болно. Мөн таны таблет түгжээтэй байсан ч тэдгээрийг дурын хүн үзэж болохыг санаарай. Зарим виджет таны түгжээтэй дэлгэцэд зориулагдаагүй байж магадгүй ба энд нэмэхэд аюултай байж болзошгүй."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ойлголоо"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Хэрэглэгчийг сэлгэх"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"эвхмэл цэс"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Энэ харилцан үйлдлийн бүх апп болон дата устах болно."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Харилцан ярианы мэдэгдлийн дээд талд болон түгжигдсэн дэлгэц дээр профайл зураг байдлаар харуулах бөгөөд бөмбөлөг хэлбэрээр харагдана. Бүү саад бол горимыг тасалдуулна"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Чухал"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь харилцан ярианы онцлогуудыг дэмждэггүй"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Эдгээр мэдэгдлийг өөрчлөх боломжгүй."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Дуудлагын мэдэгдлийг өөрчлөх боломжгүй."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Энэ бүлэг мэдэгдлийг энд тохируулах боломжгүй байна"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Илүү өндөр нягтрал авах бол утсыг хөнтөрнө үү"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Эвхэгддэг төхөөрөмжийг дэлгэж байна"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Эвхэгддэг төхөөрөмжийг хөнтөрч байна"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Нүүрэн талын дэлгэцийг асаасан"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"эвхсэн"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"дэлгэсэн"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Хандалт"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Товчлуурын шууд холбоос"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Товчлуурын шууд холбоосыг өөрчлөх"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Товчлол оноохын тулд товч дарна уу"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Товчлолууд хайх"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ямар ч хайлтын илэрц байхгүй"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Хураах дүрс тэмдэг"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Чирэх бариул"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Гарын тохиргоо"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Товчлол тохируулах"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Цуцлах"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Товч дарна уу"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Товчийн хослолыг аль хэдийн ашиглаж байна. Өөр товч туршиж үзнэ үү."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Гараа ашиглан шилжих"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Товчлуурын шууд холбоосыг мэдэж аваарай"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Мэдрэгч самбараа ашиглан шилжээрэй"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index cd90622..280a757 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"लॉक स्‍क्रीन विजेट"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"विजेट वापरून अ‍ॅप उघडण्यासाठी, तुम्हाला हे तुम्हीच असल्याची पडताळणी करावी लागेल. तसेच, लक्षात ठेवा, तुमचा टॅबलेट लॉक असतानादेखील कोणीही ती पाहू शकते. काही विजेट कदाचित तुमच्या लॉक स्‍क्रीनसाठी नाहीत आणि ती इथे जोडणे असुरक्षित असू शकते."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"समजले"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"वापरकर्ता स्विच करा"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेनू"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"या सत्रातील सर्व अ‍ॅप्स आणि डेटा हटवला जाईल."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"संभाषण सूचनांच्या वरती आणि लॉक स्क्रीनवरील प्रोफाइल फोटो म्हणून दिसते, बबल म्हणून दिसते, व्यत्यय आणू नका यामध्ये अडथळा आणते"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"प्राधान्य"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> हे संभाषण वैशिष्ट्यांना सपोर्ट करत नाही"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"या सूचनांमध्ये सुधारणा केली जाऊ शकत नाही."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"कॉलशी संबंधित सूचनांमध्ये फेरबदल केला जाऊ शकत नाही."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"या सूचनांचा संच येथे कॉन्फिगर केला जाऊ शकत नाही"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"उच्च रेझोल्यूशनसाठी, फोन फ्लिप करा"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"फोल्ड करता येण्यासारखे डिव्हाइस अनफोल्ड केले जात आहे"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"फोल्ड करता येण्यासारखे डिव्हाइस आजूबाजूला फ्लिप केले जात आहे"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"पुढील स्क्रीन सुरू केलेली आहे"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"फोल्ड केलेले"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"फोल्ड न केलेले"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"अ‍ॅक्सेसिबिलिटी"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"कीबोर्ड शॉर्टकट"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"कीबोर्ड शॉर्टकट कस्टमाइझ करा"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"शॉर्टकट असाइन करण्यासाठी की प्रेस करा"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"शोधण्यासाठी शॉर्टकट"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"कोणतेही शोध परिणाम नाहीत"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"कोलॅप्स करा आयकन"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ड्रॅग हॅंडल"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"कीबोर्ड सेटिंग्ज"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"शॉर्टकट सेट करा"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"रद्द करा"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"की प्रेस करा"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"की कॉम्बिनेशन आधीपासून वापरले जात आहे. दुसरी की वापरून पहा."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"तुमचा कीबोर्ड वापरून नेव्हिगेट करा"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"कीबोर्ड शॉर्टकट जाणून घ्या"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"तुमचा टचपॅड वापरून नेव्हिगेट करा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index c108fc4..d20262a 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widget skrin kunci"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Untuk membuka apl menggunakan widget, anda perlu mengesahkan identiti anda. Selain itu, perlu diingat bahawa sesiapa sahaja boleh melihat widget tersebut, walaupun semasa tablet anda dikunci. Sesetengah widget mungkin tidak sesuai untuk skrin kunci anda dan mungkin tidak selamat untuk ditambahkan di sini."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Tukar pengguna"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu tarik turun"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua apl dan data dalam sesi ini akan dipadam."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Ditunjukkan di bahagian atas pemberitahuan perbualan dan sebagai gambar profil pada skrin kunci, muncul sebagai gelembung, mengganggu Jangan Ganggu"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Keutamaan"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak menyokong ciri perbualan"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Pemberitahuan ini tidak boleh diubah suai."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Pemberitahuan panggilan tidak boleh diubah suai."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Kumpulan pemberitahuan ini tidak boleh dikonfigurasikan di sini"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Untuk peleraian lebih tinggi, balikkan telefon"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Peranti boleh lipat dibuka"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Peranti boleh lipat diterbalikkan"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Skrin hadapan dihidupkan"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"terlipat"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"tidak terlipat"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Kebolehaksesan"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Pintasan papan kekunci"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Sesuaikan pintasan papan kekunci"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Tekan kekunci untuk menetapkan pintasan"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pintasan carian"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Tiada hasil carian"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Kuncupkan ikon"</string>
@@ -1431,14 +1441,21 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Pemegang seret"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Tetapan Papan Kekunci"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Tetapkan pintasan"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Batal"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tekan kekunci"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Gabungan kekunci sudah digunakan. Cuba kekunci lain."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigasi menggunakan papan kekunci"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Ketahui pintasan papan kekunci"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigasi menggunakan pad sentuh anda"</string>
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Ketahui gerak isyarat pad sentuh"</string>
-    <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navigasi menggunakan papan kekunci dan pad sentuh anda"</string>
+    <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navigasi menggunakan papan kekunci dan pad sentuh"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Ketahui gerak isyarat pad sentuh, pintasan papan kekunci dan pelbagai lagi"</string>
     <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Kembali"</string>
     <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Akses laman utama"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index ce52f4e..b77f037 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"လော့ခ်မျက်နှာပြင် ဝိဂျက်များ"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ဝိဂျက်သုံး၍ အက်ပ်ဖွင့်ရန်အတွက် သင်ဖြစ်ကြောင်း အတည်ပြုရန်လိုသည်။ ထို့ပြင် သင့်တက်ဘလက် လော့ခ်ချထားချိန်၌ပင် မည်သူမဆို ၎င်းတို့ကို ကြည့်နိုင်ကြောင်း သတိပြုပါ။ ဝိဂျက်အချို့ကို လော့ခ်မျက်နှာပြင်အတွက် ရည်ရွယ်ထားခြင်း မရှိသဖြင့် ဤနေရာတွင် ထည့်ပါက မလုံခြုံနိုင်ပါ။"</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"နားလည်ပြီ"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"အသုံးပြုသူကို ပြောင်းလဲရန်"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ဆွဲချမီနူး"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ဒီချိတ်ဆက်မှု ထဲက အက်ပ်များ အားလုံး နှင့် ဒေတာကို ဖျက်ပစ်မည်။"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"စကားဝိုင်း အကြောင်းကြားချက်များ၏ ထိပ်ပိုင်းနှင့် ပရိုဖိုင်ပုံအဖြစ် လော့ခ်မျက်နှာပြင်တွင် ပြသည်။ ပူဖောင်းကွက်အဖြစ် မြင်ရပြီး ‘မနှောင့်ယှက်ရ’ ကို ကြားဖြတ်သည်"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"ဦးစားပေး"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> က စကားဝိုင်းဝန်ဆောင်မှုများကို မပံ့ပိုးပါ"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"ဤအကြောင်းကြားချက်များကို ပြုပြင်၍ မရပါ။"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"ခေါ်ဆိုမှုအကြောင်းကြားချက်များကို ပြင်၍မရပါ။"</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"ဤအကြောင်းကြားချက်အုပ်စုကို ဤနေရာတွင် စီစဉ်သတ်မှတ်၍ မရပါ"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"ပုံရိပ် ပိုမိုပြတ်သားစေရန် ဖုန်းကို တစ်ဖက်သို့ လှန်လိုက်ပါ"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ခေါက်နိုင်သောစက်ကို ဖြန့်လိုက်သည်"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ခေါက်နိုင်သောစက်ကို တစ်ဘက်သို့ လှန်လိုက်သည်"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ရှေ့စခရင် ဖွင့်ထားသည်"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ခေါက်ထားသည်"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ဖြန့်ထားသည်"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"အများသုံးနိုင်မှု"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"လက်ကွက်ဖြတ်လမ်းများ"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"လက်ကွက်ဖြတ်လမ်းများကို စိတ်ကြိုက်လုပ်ခြင်း"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"ဖြတ်လမ်းသတ်မှတ်ရန် ကီးကို နှိပ်ပါ"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ဖြတ်လမ်းများ ရှာရန်"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ရှာဖွေမှုရလဒ် မရှိပါ"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"လျှော့ပြရန် သင်္ကေတ"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ဖိဆွဲအထိန်း"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"ကီးဘုတ်ဆက်တင်များ"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ဖြတ်လမ်း သတ်မှတ်ရန်"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"မလုပ်တော့"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ကီးကို နှိပ်ပါ"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"ကီးပေါင်းစပ်ခြင်းကို သုံးနေပြီးဖြစ်သည်။ အခြားကီးကို စမ်းကြည့်ပါ။"</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"သင့်ကီးဘုတ်ကိုသုံး၍ လမ်းညွှန်ခြင်း"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"လက်ကွက်ဖြတ်လမ်းများကို လေ့လာပါ"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"သင့်တာ့ချ်ပက်ကိုသုံး၍ လမ်းညွှန်ခြင်း"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index db352a5..fa4886b 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Låseskjermmoduler"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"For å åpne en app ved hjelp av en modul må du bekrefte at det er deg. Husk også at hvem som helst kan se dem, selv om nettbrettet er låst. Noen moduler er kanskje ikke laget for å være på låseskjermen og kan være utrygge å legge til der."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Greit"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Bytt bruker"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullegardinmeny"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apper og data i denne økten blir slettet."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Vises øverst på samtalevarsler og som et profilbilde på låseskjermen, vises som en boble, avbryter «Ikke forstyrr»"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> støtter ikke samtalefunksjoner"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Disse varslene kan ikke endres."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Anropsvarsler kan ikke endres."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Denne varselgruppen kan ikke konfigureres her"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Brett ut telefonen for å få høyere oppløsning"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"En foldbar enhet blir brettet ut"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"En foldbar enhet blir snudd"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Frontskjermen er slått på"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"lagt sammen"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"åpen"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Tilgjengelighet"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Hurtigtaster"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Tilpass hurtigtastene"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Trykk på tasten for å tilordne hurtigtasten"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Snarveier til søk"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ingen søkeresultater"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Skjul-ikon"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Håndtak"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Tastaturinnstillinger"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Angi hurtigtast"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Avbryt"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Trykk på tasten"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Tastekombinasjonen brukes allerede. Prøv en annen tast."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviger med tastaturet"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Lær deg hurtigtaster"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviger med styreflaten"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 2c1d727..babc0d1 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"लक स्क्रिन विजेटहरू"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"विजेट प्रयोग गरी एप खोल्न तपाईंले आफ्नो पहिचान पुष्टि गर्नु पर्ने हुन्छ। साथै, तपाईंको ट्याब्लेट लक भएका बेला पनि सबै जनाले तिनलाई देख्न सक्छन् भन्ने कुरा ख्याल गर्नुहोस्। केही विजेटहरू लक स्क्रिनमा प्रयोग गर्ने उद्देश्यले नबनाइएका हुन सक्छन् र तिनलाई यहाँ हाल्नु सुरक्षित नहुन सक्छ।"</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"बुझेँ"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"प्रयोगकर्ता फेर्नुहोस्"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेनु"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"यो सत्रमा भएका सबै एपहरू र डेटा मेटाइने छ।"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"यो वार्तालापका सूचनाहरूको सिरानमा, बबलका रूपमा र लक स्क्रिनमा प्रोफाइल फोटोका रूपमा देखिन्छ। साथै, यसले गर्दा \'बाधा नपुऱ्याउनुहोस्\' नामक सुविधामा अवरोध आउँछ"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा वार्तालापसम्बन्धी सुविधा प्रयोग गर्न मिल्दैन"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"यी सूचनाहरू परिमार्जन गर्न मिल्दैन।"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"कलसम्बन्धी सूचनाहरू परिमार्जन गर्न मिल्दैन।"</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"यहाँबाट सूचनाहरूको यो समूह कन्फिगर गर्न सकिँदैन"</string>
@@ -1355,10 +1361,9 @@
     <string name="rear_display_unfolded_bottom_sheet_title" msgid="6291111173057304055">"स्क्रिनहरू बदल्ने हो?"</string>
     <string name="rear_display_folded_bottom_sheet_description" msgid="6842767125783222695">"उच्च रिजोल्युसनको सेल्फी खिच्न पछाडिको क्यामेरा प्रयोग गर्नुहोस्"</string>
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"उच्च रिजोल्युसनको सेल्फी खिच्न फोन फ्लिप गर्नुहोस्"</string>
-    <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"फोल्ड गर्न मिल्ने डिभाइस अनफोल्ड गरेको देखाइएको एनिमेसन"</string>
-    <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"फोल्ड गर्न मिल्ने डिभाइस यताउता पल्टाएर देखाइएको एनिमेसन"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"फोल्डेबल डिभाइस अनफोल्ड गरेको देखाइएको एनिमेसन"</string>
+    <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"फोल्डेबल डिभाइस यताउता पल्टाएर देखाइएको एनिमेसन"</string>
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"अगाडिको स्क्रिन अन गरिएको छ"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"फोल्ड गरिएको"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"अनफोल्ड गरिएको"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"सर्वसुलभता"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"किबोर्डका सर्टकटहरू"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"किबोर्डका सर्टकटहरू कस्टमाइज गर्नुहोस्"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"सर्टकट असाइन गर्न की थिच्नुहोस्"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"खोजका सर्टकटहरू"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"कुनै पनि खोज परिणाम भेटिएन"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"\"कोल्याप्स गर्नुहोस्\" आइकन"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ड्र्याग ह्यान्डल"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"किबोर्डसम्बन्धी सेटिङ"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"सर्टकट सेट गर्नुहोस्"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"रद्द गर्नुहोस्"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"की थिच्नुहोस्"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"यो की कम्बिनेसन प्रयोग गरिसकिएको छ। अर्कै की प्रयोग गरी हेर्नुहोस्।"</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"किबोर्ड प्रयोग गरी नेभिगेट गर्नुहोस्"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"किबोर्डका सर्टकटहरू प्रयोग गर्न सिक्नुहोस्"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"टचप्याड प्रयोग गरी नेभिगेट गर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 0d195a3..61c4bd54 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets op het vergrendelscherm"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Als je een app wilt openen met een widget, moet je verifiëren dat jij het bent. Houd er ook rekening mee dat iedereen ze kan bekijken, ook als je tablet vergrendeld is. Bepaalde widgets zijn misschien niet bedoeld voor je vergrendelscherm en kunnen hier niet veilig worden toegevoegd."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Gebruiker wijzigen"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pull-downmenu"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps en gegevens in deze sessie worden verwijderd."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Wordt getoond bovenaan gespreksmeldingen en als profielfoto op het vergrendelscherm, verschijnt als bubbel, onderbreekt Niet storen"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ondersteunt geen gespreksfuncties"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Deze meldingen kunnen niet worden aangepast."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Gespreksmeldingen kunnen niet worden aangepast."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Deze groep meldingen kan hier niet worden ingesteld"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Gebruik minder dan <xliff:g id="LENGTH">%1$d</xliff:g> tekens"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildnummer"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Buildnummer naar klembord gekopieerd."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"kopiëren naar klembord."</string>
     <string name="basic_status" msgid="2315371112182658176">"Gesprek openen"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Gesprekswidgets"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Tik op een gesprek om het toe te voegen aan je startscherm"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Draai de telefoon om voor een hogere resolutie"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Opvouwbaar apparaat wordt uitgevouwen"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Opvouwbaar apparaat wordt gedraaid"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Scherm aan voorzijde aangezet"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"dichtgevouwen"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"opengevouwen"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Toegankelijkheid"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Sneltoetsen"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Sneltoetsen aanpassen"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Druk op de toets om de sneltoets toe te wijzen"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Sneltoetsen zoeken"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Geen zoekresultaten"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icoon voor samenvouwen"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Handgreep voor slepen"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Toetsenbordinstellingen"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Sneltoets instellen"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Annuleren"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Druk op een toets"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Toetsencombinatie is al in gebruik. Probeer een andere toets."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigeren met je toetsenbord"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Leer sneltoetsen die je kunt gebruiken"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigeren met je touchpad"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 181315b..e932e74 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ଲକ ସ୍କ୍ରିନ ୱିଜେଟ"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ଏକ ୱିଜେଟ ବ୍ୟବହାର କରି ଗୋଟିଏ ଆପ ଖୋଲିବା ପାଇଁ ଏହା ଆପଣ ଅଟନ୍ତି ବୋଲି ଆପଣଙ୍କୁ ଯାଞ୍ଚ କରିବାକୁ ହେବ। ଆହୁରି ମଧ୍ୟ, ଆପଣଙ୍କ ଟାବଲେଟ ଲକ ଥିଲେ ମଧ୍ୟ ଯେ କୌଣସି ବ୍ୟକ୍ତି ଏହାକୁ ଭ୍ୟୁ କରିପାରିବେ ବୋଲି ମନେ ରଖନ୍ତୁ। କିଛି ୱିଜେଟ ଆପଣଙ୍କ ଲକ ସ୍କ୍ରିନ ପାଇଁ ଉଦ୍ଦିଷ୍ଟ ହୋଇନଥାଇପାରେ ଏବଂ ଏଠାରେ ଯୋଗ କରିବା ଅସୁରକ୍ଷିତ ହୋଇପାରେ।"</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ବୁଝିଗଲି"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ୟୁଜର୍‍ ବଦଳାନ୍ତୁ"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ପୁଲଡାଉନ ମେନୁ"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ଏହି ସେସନର ସମସ୍ତ ଆପ୍‌ ଓ ଡାଟା ଡିଲିଟ୍‌ ହୋଇଯିବ।"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"ବାର୍ତ୍ତାଳାପ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଶୀର୍ଷରେ ଏବଂ ଲକ୍ ସ୍କ୍ରିନରେ ଏକ ପ୍ରୋଫାଇଲ୍ ଛବି ଭାବେ ଦେଖାଏ, ଏକ ବବଲ୍ ଭାବେ ଦେଖାଯାଏ, \'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\'କୁ ବାଧା ଦିଏ"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"ପ୍ରାଥମିକତା"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବାର୍ତ୍ତାଳାପ ଫିଚରଗୁଡ଼ିକୁ ସମର୍ଥନ କରେ ନାହିଁ"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ପରିବର୍ତ୍ତନ କରିହେବ ନାହିଁ।"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"କଲ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ପରିବର୍ତ୍ତନ କରାଯାଇପାରିବ ନାହିଁ।"</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"ଏଠାରେ ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଗ୍ରୁପ୍ କନଫ୍ୟୁଗର୍ କରାଯାଇପାରିବ ନାହିଁ"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"ଉଚ୍ଚ ରିଜୋଲ୍ୟୁସନ ପାଇଁ ଫୋନକୁ ଫ୍ଲିପ କରନ୍ତୁ"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ଫୋଲ୍ଡ କରାଯାଇପାରୁଥିବା ଡିଭାଇସକୁ ଅନଫୋଲ୍ଡ କରାଯାଉଛି"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ଫୋଲ୍ଡ କରାଯାଇପାରୁଥିବା ଡିଭାଇସକୁ ଫ୍ଲିପ କରାଯାଉଛି"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ସାମ୍ନା ସ୍କ୍ରିନ ଚାଲୁ ଅଛି"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ଫୋଲ୍ଡେଡ"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ଅନଫୋଲ୍ଡେଡ"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ଆକ୍ସେସିବିଲିଟୀ"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"କୀବୋର୍ଡ ସର୍ଟକଟ"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"କୀବୋର୍ଡ ସର୍ଟକଟଗୁଡ଼ିକୁ କଷ୍ଟମାଇଜ କରନ୍ତୁ"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"ସର୍ଟକଟ ଆସାଇନ କରିବା ପାଇଁ କୀ\'କୁ ଦବାନ୍ତୁ"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ସର୍ଚ୍ଚ ସର୍ଟକଟ"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"କୌଣସି ସର୍ଚ୍ଚ ଫଳାଫଳ ନାହିଁ"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ଆଇକନକୁ ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ଡ୍ରାଗ ହେଣ୍ଡେଲ"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"କୀବୋର୍ଡ ସେଟିଂ"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ସର୍ଟକଟ ସେଟ କରନ୍ତୁ"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ବାତିଲ କରନ୍ତୁ"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"କୀ ଦବାନ୍ତୁ"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"କୀ କମ୍ବିନେସନ ପୂର୍ବରୁ ବ୍ୟବହାର କରାଯାଉଛି। ଅନ୍ୟ ଏକ କୀ ବ୍ୟବହାର କରି ଦେଖନ୍ତୁ।"</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ଆପଣଙ୍କ କୀବୋର୍ଡ ବ୍ୟବହାର କରି ନାଭିଗେଟ କରନ୍ତୁ"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"କୀବୋର୍ଡ ସର୍ଟକଟଗୁଡ଼ିକ ବିଷୟରେ ଜାଣନ୍ତୁ"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ଆପଣଙ୍କ ଟଚପେଡ ବ୍ୟବହାର କରି ନାଭିଗେଟ କରନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 5b9919e..80798b7 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ਲਾਕ ਸਕ੍ਰੀਨ ਵਿਜੇਟ"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ਵਿਜੇਟ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਐਪ ਖੋਲ੍ਹਣ ਲਈ, ਤੁਹਾਨੂੰ ਇਹ ਪੁਸ਼ਟੀ ਕਰਨ ਦੀ ਲੋੜ ਪਵੇਗੀ ਕਿ ਇਹ ਤੁਸੀਂ ਹੀ ਹੋ। ਨਾਲ ਹੀ, ਇਹ ਵੀ ਧਿਆਨ ਵਿੱਚ ਰੱਖੋ ਕਿ ਕੋਈ ਵੀ ਉਨ੍ਹਾਂ ਨੂੰ ਦੇਖ ਸਕਦਾ ਹੈ, ਭਾਵੇਂ ਤੁਹਾਡਾ ਟੈਬਲੈੱਟ ਲਾਕ ਹੋਵੇ। ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਕੁਝ ਵਿਜੇਟ ਤੁਹਾਡੀ ਲਾਕ ਸਕ੍ਰੀਨ ਲਈ ਨਾ ਬਣੇ ਹੋਣ ਅਤੇ ਉਨ੍ਹਾਂ ਨੂੰ ਇੱਥੇ ਸ਼ਾਮਲ ਕਰਨਾ ਅਸੁਰੱਖਿਅਤ ਹੋਵੇ।"</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ਸਮਝ ਲਿਆ"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ਵਰਤੋਂਕਾਰ ਸਵਿੱਚ ਕਰੋ"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ਪੁੱਲਡਾਊਨ ਮੀਨੂ"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ਇਸ ਸੈਸ਼ਨ ਵਿਚਲੀਆਂ ਸਾਰੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟੇ ਨੂੰ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"ਗੱਲਬਾਤ ਸੂਚਨਾਵਾਂ ਦੇ ਸਿਖਰ \'ਤੇ ਅਤੇ ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ ਵਜੋਂ ਦਿਖਾਈਆਂ ਜਾਂਦੀਆਂ ਹਨ, ਜੋ ਕਿ ਬਬਲ ਵਜੋਂ ਦਿਸਦੀਆਂ ਹਨ ਅਤੇ \'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਸੁਵਿਧਾ ਵਿੱਚ ਵਿਘਨ ਵੀ ਪਾ ਸਕਦੀਆਂ ਹਨ"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"ਤਰਜੀਹ"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਗੱਲਬਾਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਸੋਧਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"ਕਾਲ ਸੰਬੰਧੀ ਸੂਚਨਾਵਾਂ ਨੂੰ ਸੋਧਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"ਇਹ ਸੂਚਨਾਵਾਂ ਦਾ ਗਰੁੱਪ ਇੱਥੇ ਸੰਰੂਪਿਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"ਉੱਚ ਰੈਜ਼ੋਲਿਊਸ਼ਨ ਲਈ, ਫ਼ੋਨ ਨੂੰ ਫਲਿੱਪ ਕਰੋ"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ਮੋੜਨਯੋਗ ਡੀਵਾਈਸ ਨੂੰ ਖੋਲ੍ਹਿਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ਮੋੜਨਯੋਗ ਡੀਵਾਈਸ ਨੂੰ ਆਲੇ-ਦੁਆਲੇ ਫਲਿੱਪ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ਅਗਲੀ ਸਕ੍ਰੀਨ ਚਾਲੂ ਕੀਤੀ ਗਈ"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ਫੋਲਡਯੋਗ ਡੀਵਾਈਸ"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ਅਣਫੋਲਡਯੋਗ ਡੀਵਾਈਸ"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ਪਹੁੰਚਯੋਗਤਾ"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ ਵਿਉਂਤਬੱਧ ਕਰੋ"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"ਸ਼ਾਰਟਕੱਟ ਨਿਰਧਾਰਿਤ ਕਰਨ ਲਈ ਕੁੰਜੀ ਦਬਾਓ"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ਸ਼ਾਰਟਕੱਟ ਖੋਜੋ"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ਕੋਈ ਖੋਜ ਨਤੀਜਾ ਨਹੀਂ ਮਿਲਿਆ"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ਪ੍ਰਤੀਕ ਨੂੰ ਸਮੇਟੋ"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ਘਸੀਟਣ ਵਾਲਾ ਹੈਂਡਲ"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"ਕੀ-ਬੋਰਡ ਸੈਟਿੰਗਾਂ"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ਸ਼ਾਰਟਕੱਟ ਸੈੱਟ ਕਰੋ"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ਰੱਦ ਕਰੋ"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ਕੁੰਜੀ ਦਬਾਓ"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"ਕੁੰਜੀ ਸੁਮੇਲ ਪਹਿਲਾਂ ਹੀ ਵਰਤੋਂ ਵਿੱਚ ਹੈ। ਕੋਈ ਹੋਰ ਕੁੰਜੀ ਨੂੰ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ਆਪਣੇ ਕੀ-ਬੋਰਡ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਨੈਵੀਗੇਟ ਕਰੋ"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ਕੀ-ਬੋਰਡ ਦੇ ਸ਼ਾਰਟਕੱਟਾਂ ਬਾਰੇ ਜਾਣੋ"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ਆਪਣੇ ਟੱਚਪੈਡ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਨੈਵੀਗੇਟ ਕਰੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index e41d16f..67fdf8c 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widżety na ekranie blokady"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Aby otworzyć aplikację za pomocą widżetu, musisz potwierdzić swoją tożsamość. Pamiętaj też, że każdy będzie mógł wyświetlić widżety nawet wtedy, gdy tablet będzie zablokowany. Niektóre widżety mogą nie być przeznaczone do umieszczenia na ekranie blokady i ich dodanie w tym miejscu może być niebezpieczne."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Przełącz użytkownika"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wszystkie aplikacje i dane w tej sesji zostaną usunięte."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Wyświetla się u góry powiadomień w rozmowach oraz jako zdjęcie profilowe na ekranie blokady, jako dymek, przerywa działanie trybu Nie przeszkadzać"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Priorytetowe"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje funkcji rozmów"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Tych powiadomień nie można zmodyfikować."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Powiadomień o połączeniach nie można modyfikować."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Tej grupy powiadomień nie można tu skonfigurować"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Wpisz mniej znaków niż <xliff:g id="LENGTH">%1$d</xliff:g>"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Numer kompilacji"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Numer kompilacji został skopiowany do schowka."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"Kopiuj do schowka"</string>
     <string name="basic_status" msgid="2315371112182658176">"Otwarta rozmowa"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widżety rozmów"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Kliknij rozmowę, aby dodać ją do ekranu głównego"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Odwróć telefon, aby uzyskać wyższą rozdzielczość"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Składane urządzenie jest rozkładane"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Składane urządzenie jest obracane"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Ekran przedni jest włączony"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"po zamknięciu"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"po otwarciu"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Ułatwienia dostępu"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Skróty klawiszowe"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Dostosuj skróty klawiszowe"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Naciśnij klawisz, aby przypisać skrót"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Skróty do wyszukiwania"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Brak wyników wyszukiwania"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona zwijania"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Uchwyt do przeciągania"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Ustawienia klawiatury"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Ustaw skrót"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Anuluj"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Naciśnij klawisz"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Kombinacja klawiszy jest już używana. Użyj innego klawisza."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Nawiguj za pomocą klawiatury"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Dowiedz się więcej o skrótach klawiszowych"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Nawiguj za pomocą touchpada"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 72e593c..7db8d8d 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets da tela de bloqueio"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir um app usando um widget, você precisa confirmar sua identidade. E não se esqueça que qualquer pessoa pode ver os widgets, mesmo com o tablet bloqueado. Além disso, alguns apps não foram criados para a tela de bloqueio, é melhor manter a segurança."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Entendi"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Trocar usuário"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu suspenso"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Aparecem na parte superior das notificações de conversa, como uma foto do perfil na tela de bloqueio e como um balão. Interrompem o Não perturbe."</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritárias"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com recursos de conversa"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar essas notificações."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Não é possível modificar as notificações de chamada."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Não é possível configurar esse grupo de notificações aqui"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Para uma resolução maior, vire o smartphone"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo dobrável sendo aberto"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo dobrável sendo virado"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Tela frontal ativada"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"fechado"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aberto"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Acessibilidade"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Atalhos do teclado"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizar atalhos de teclado"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Pressione a tecla para atribuir o atalho"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pesquisar atalhos"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nenhum resultado de pesquisa"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone \"Fechar\""</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Alça de arrastar"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Configurações do teclado"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Definir atalho"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pressione a tecla"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Essa combinação de teclas já está em uso. Tente outra tecla."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navegue usando o teclado"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprenda atalhos do teclado"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navegue usando o touchpad"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 460d553..d9d82bf 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -528,6 +528,8 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets do ecrã de bloqueio"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir uma app através de um widget, vai ter de validar a sua identidade. Além disso, tenha em atenção que qualquer pessoa pode ver os widgets, mesmo quando o tablet estiver bloqueado. Alguns widgets podem não se destinar ao ecrã de bloqueio e pode ser inseguro adicioná-los aqui."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string>
+    <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string>
+    <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="511359420883794513">"Para adicionar widgets ao ecrã de bloqueio como um atalho, certifique-se de que estão ativados nas definições."</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mudar utilizador"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu pendente"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todas as apps e dados desta sessão serão eliminados."</string>
@@ -780,6 +782,7 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Aparece na parte superior das notificações de conversas e como uma imagem do perfil no ecrã de bloqueio, surge como um balão, interrompe o modo Não incomodar"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> não suporta funcionalidades de conversa."</string>
+    <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Enviar feedback sobre o pacote"</string>
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar estas notificações."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Não é possível modificar as notificações de chamadas."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Não é possível configurar este grupo de notificações aqui."</string>
@@ -1220,8 +1223,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use menos de <xliff:g id="LENGTH">%1$d</xliff:g> carateres"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da compilação"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Número da compilação copiado para a área de transferência."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"copiar para a área de transferência."</string>
     <string name="basic_status" msgid="2315371112182658176">"Abrir conversa"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversa"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Toque numa conversa para a adicionar ao ecrã principal"</string>
@@ -1357,8 +1359,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Para uma resolução superior, inverta o telemóvel"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo dobrável a ser desdobrado"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo dobrável a ser virado ao contrário"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Ecrã frontal ativado"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"fechado"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aberto"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1419,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Acessibilidade"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Atalhos de teclado"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalize os atalhos de teclado"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Prima a tecla para atribuir o atalho"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pesquisar atalhos"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nenhum resultado da pesquisa"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone de reduzir"</string>
@@ -1431,9 +1437,13 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Indicador para arrastar"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Definições do teclado"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Configurar atalho"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Prima a tecla"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"A combinação de teclas já está a ser usada. Experimente outra tecla."</string>
+    <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"A combinação de teclas já está a ser usada. Experimente outra tecla."</string>
+    <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Não é possível definir o atalho."</string>
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navegue com o teclado"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprenda atalhos de teclado"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navegue com o touchpad"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 72e593c..7db8d8d 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets da tela de bloqueio"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir um app usando um widget, você precisa confirmar sua identidade. E não se esqueça que qualquer pessoa pode ver os widgets, mesmo com o tablet bloqueado. Além disso, alguns apps não foram criados para a tela de bloqueio, é melhor manter a segurança."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Entendi"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Trocar usuário"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu suspenso"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Aparecem na parte superior das notificações de conversa, como uma foto do perfil na tela de bloqueio e como um balão. Interrompem o Não perturbe."</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritárias"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com recursos de conversa"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar essas notificações."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Não é possível modificar as notificações de chamada."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Não é possível configurar esse grupo de notificações aqui"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Para uma resolução maior, vire o smartphone"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo dobrável sendo aberto"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo dobrável sendo virado"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Tela frontal ativada"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"fechado"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aberto"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Acessibilidade"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Atalhos do teclado"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizar atalhos de teclado"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Pressione a tecla para atribuir o atalho"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pesquisar atalhos"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nenhum resultado de pesquisa"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone \"Fechar\""</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Alça de arrastar"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Configurações do teclado"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Definir atalho"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pressione a tecla"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Essa combinação de teclas já está em uso. Tente outra tecla."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navegue usando o teclado"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprenda atalhos do teclado"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navegue usando o touchpad"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 42fd14b..60e5b8a 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgeturi pe ecranul de blocare"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Pentru a deschide o aplicație folosind un widget, va trebui să-ți confirmi identitatea. În plus, reține că oricine poate să vadă widgeturile, chiar dacă tableta este blocată. Este posibil ca unele widgeturi să nu fi fost create pentru ecranul de blocare și poate fi nesigur să le adaugi aici."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Schimbă utilizatorul"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"meniu vertical"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toate aplicațiile și datele din această sesiune vor fi șterse."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Se afișează în partea de sus a notificărilor pentru conversații și ca fotografie de profil pe ecranul de blocare, apare ca un balon, întrerupe funcția Nu deranja"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritate"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu acceptă funcții pentru conversații"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Aceste notificări nu pot fi modificate."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Notificările pentru apeluri nu pot fi modificate."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Acest grup de notificări nu poate fi configurat aici"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Pentru o rezoluție mai mare, deschide telefonul"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispozitiv pliabil care este desfăcut"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispozitiv pliabil care este întors"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Ecranul frontal este activat"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"închis"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"deschis"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accesibilitate"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Comenzi rapide de la tastatură"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizează comenzile rapide de la tastatură"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Apasă tasta pentru a atribui comanda rapidă"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Comenzi directe de căutare"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Niciun rezultat al căutării"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Pictograma de restrângere"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Ghidaj de tragere"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Setările tastaturii"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Setează o comandă rapidă"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Anulează"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Apasă tasta"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Combinația de taste este deja folosită. Încearcă altă tastă."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navighează folosind tastatura"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Învață comenzile rapide de la tastatură"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navighează folosind touchpadul"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 866cb5e..2707e4b 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Виджеты на заблокированном экране"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Чтобы открыть приложение, используя виджет, вам нужно будет подтвердить свою личность. Обратите внимание, что виджеты видны всем, даже если планшет заблокирован. Некоторые виджеты не предназначены для использования на заблокированном экране. Добавлять их туда может быть небезопасно."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ОК"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Сменить пользователя."</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"раскрывающееся меню"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Все приложения и данные этого профиля будут удалены."</string>
@@ -698,8 +702,8 @@
     <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Контроль шума"</string>
     <string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"Пространственное звучание"</string>
     <string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"Отключено"</string>
-    <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Без отсле­живания"</string>
-    <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"С отсле­живанием"</string>
+    <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Статичное"</string>
+    <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Динамичное"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Нажмите, чтобы изменить режим звонка."</string>
     <string name="volume_ringer_mode" msgid="6867838048430807128">"режим звонка"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"отключить звук"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Появляется в верхней части уведомлений о сообщениях, в виде всплывающего чата, а также в качестве фото профиля на заблокированном экране, прерывает режим \"Не беспокоить\"."</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" не поддерживает функции разговоров."</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Эти уведомления нельзя изменить."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Уведомления о звонках нельзя изменить."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Эту группу уведомлений нельзя настроить здесь."</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Переверните телефон и используйте основную камеру, чтобы делать снимки с более высоким разрешением."</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Складное устройство в разложенном виде"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Перевернутое складное устройство"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Передний экран включен"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"устройство сложено"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"устройство разложено"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Специальные возможности"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Быстрые клавиши"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Как настроить быстрые клавиши"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Нажмите клавишу, чтобы назначить быструю команду."</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Найти быстрые клавиши"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ничего не найдено"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок \"Свернуть\""</string>
@@ -1431,15 +1441,22 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Маркер перемещения"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Настройки клавиатуры"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Задать сочетание клавиш"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Отмена"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Нажмите клавишу"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Это сочетание клавиш уже используется. Попробуйте другое."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Навигация с помощью клавиатуры"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Узнайте о сочетаниях клавиш."</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Навигация с помощью сенсорной панели"</string>
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Узнайте о жестах на сенсорной панели."</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Навигация с помощью клавиатуры и сенсорной панели"</string>
-    <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Узнайте о жестах на сенсорной панели, сочетаниях клавиш и многом другом."</string>
+    <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Выучите жесты на сенсорной панели, сочетания клавиш и другие варианты навигации."</string>
     <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Назад"</string>
     <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"На главный экран"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Просмотр недавних приложений"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 0ccd61c..761d8fe 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"අගුළු තිර විජට්"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"විජට් එකක් භාවිතයෙන් යෙදුමක් විවෘත කිරීමට, ඔබට ඒ ඔබ බව සත්‍යාපනය කිරීමට අවශ්‍ය වනු ඇත. එසේම, ඔබේ ටැබ්ලටය අගුළු දමා ඇති විට පවා ඕනෑම කෙනෙකුට ඒවා බැලිය හැකි බව මතක තබා ගන්න. සමහර විජට් ඔබේ අගුළු තිරය සඳහා අදහස් කර නොතිබිය හැකි අතර මෙහි එක් කිරීමට අනාරක්ෂිත විය හැක."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"තේරුණා"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"පරිශීලක මාරුව"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"නිපතන මෙනුව"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"මෙම සැසියේ සියළුම යෙදුම් සහ දත්ත මකාවී."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"සංවාද දැනුම්දීම්වල ඉහළින්ම සහ අගුලු තිරයේ ඇති පැතිකඩ පින්තූරයක් ලෙස පෙන්වයි, බුබුළක් ලෙස දිස් වේ, බාධා නොකරන්න සඳහා බාධා කරයි"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"ප්‍රමුඛතාව"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> සංවාද විශේෂාංගවලට සහාය නොදක්වයි"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"මෙම දැනුම්දීම් වෙනස් කළ නොහැක."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"ඇමතුම් දැනුම්දීම් වෙනස් කළ නොහැකිය."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"මෙම දැනුම්දීම් සමූහය මෙහි වින්‍යාස කළ නොහැක"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"ඉහළ විභේදනය සඳහා, දුරකථනය හරවන්න"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"දිග හැරෙමින් පවතින නැමිය හැකි උපාංගය"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"වටා පෙරළෙමින් තිබෙන නැමිය හැකි උපාංගය"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ඉදිරිපස තිරය ක්‍රියාත්මකයි"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"නැවූ"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"නොනැවූ"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ප්‍රවේශ්‍යතාව"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"යතුරු පුවරු කෙටි මං"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"යතුරුපුවරු කෙටිමං අභිරුචිකරණය කරන්න"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"කෙටි මග පැවරීමට යතුර ඔබන්න"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"කෙටි මං සොයන්න"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"සෙවීම් ප්‍රතිඵල නැත"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"හැකුළුම් නිරූපකය"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ඇදීම් හැඬලය"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"යතුරු පුවරු සැකසීම්"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"කෙටිමඟ සකසන්න"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"අවලංගු කරන්න"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"යතුර ඔබන්න"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"යතුරු සංයෝජනය දැනටමත් භාවිත වේ. වෙනත් යතුරක් උත්සාහ කරන්න."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ඔබේ යතුරු පුවරුව භාවිතයෙන් සංචාලනය කරන්න"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"යතුරුපුවරු කෙටිමං ඉගෙන ගන්න"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ඔබේ ස්පර්ශ පෑඩ් භාවිතයෙන් සංචාලනය කරන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index cc59bea..88aa12d 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Miniaplikácie na uzamknutej obrazovke"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Ak chcete otvoriť aplikáciu pomocou miniaplikácie, budete musieť overiť svoju totožnosť. Pamätajte, že si miniaplikáciu môže pozrieť ktokoľvek, aj keď máte tablet uzamknutý. Niektoré miniaplikácie možno nie sú určené pre uzamknutú obrazovku a ich pridanie tu môže byť nebezpečné."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Dobre"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Prepnutie používateľa"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rozbaľovacia ponuka"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Všetky aplikácie a údaje v tejto relácii budú odstránené."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Zobrazuje sa ako bublina v hornej časti upozornení konverzácie a profilová fotka na uzamknutej obrazovke, preruší režim bez vyrušení"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritné"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nepodporuje funkcie konverzácie"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Tieto upozornenia sa nedajú upraviť."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Upozornenia na hovory sa nedajú upraviť."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Túto skupinu upozornení nejde na tomto mieste konfigurovať"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Ak chcete vyššie rozlíšenie, prevráťte telefón"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Rozloženie skladacieho zariadenia"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Prevrátenie skladacieho zariadenia"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Predná obrazovka je zapnutá"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zložené"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"rozložené"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Dostupnosť"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Klávesové skratky"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prispôsobenie klávesových skratiek"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Stlačením klávesa priraďte skratku"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prehľadávať skratky"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Žiadne výsledky vyhľadávania"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona zbalenia"</string>
@@ -1431,14 +1441,21 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Presúvadlo"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Nastavenia klávesnice"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Nastaviť skratku"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Zrušiť"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Stlačte kláves"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Kombinácia klávesov sa už používa. Skúste iný kláves."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Pohybujte sa v systéme pomocou klávesnice"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Naučte sa klávesové skratky"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Pohybujte sa v systéme pomocou touchpadu"</string>
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Naučte sa gestá touchpadu"</string>
-    <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Prechádzajte pomocou klávesnice a touchpadu"</string>
+    <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Pohybujte sa v systéme pomocou klávesnice a touchpadu"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Naučte sa gestá touchpadu, klávesové skratky a ďalšie funkcie"</string>
     <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Prechod späť"</string>
     <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Prejsť na plochu"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 38f1e5a..4704e98 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Pripomočki na zaklenjenem zaslonu"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Če želite aplikacijo odpreti s pripomočkom, morate potrditi, da ste to vi. Upoštevajte tudi, da si jih lahko ogledajo vsi, tudi ko je tablični računalnik zaklenjen. Nekateri pripomočki morda niso predvideni za uporabo na zaklenjenem zaslonu, zato jih tukaj morda ni varno dodati."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Razumem"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Preklop med uporabniki"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"spustni meni"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Vse aplikacije in podatki v tej seji bodo izbrisani."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikaz v obliki oblačka na vrhu razdelka z obvestili za pogovor in kot profilna slika na zaklenjenem zaslonu, preglasitev načina Ne moti."</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prednostno"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podpira pogovornih funkcij."</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Za ta obvestila ni mogoče spremeniti nastavitev."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Obvestil o klicih ni mogoče spreminjati."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Te skupine obvestil ni mogoče konfigurirati tukaj"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Uporabite manj kot <xliff:g id="LENGTH">%1$d</xliff:g> znakov."</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Delovna različica"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Delovna različica je bila kopirana v odložišče."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"kopiranje v odložišče."</string>
     <string name="basic_status" msgid="2315371112182658176">"Odprt pogovor"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Pripomočki za pogovore"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Dotaknite se pogovora, da ga dodate na začetni zaslon."</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Za višjo ločljivost obrnite telefon"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Razpiranje zložljive naprave"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Obračanje zložljive naprave"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Sprednji zaslon je vklopljen"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zaprto"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"razprto"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Dostopnost"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Bližnjične tipke"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prilagajanje bližnjičnih tipk"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Pritisnite tipko za dodelitev bližnjice"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Iskanje po bližnjicah"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ni rezultatov iskanja"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za strnitev"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Ročica za vlečenje"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Nastavitve tipkovnice"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Nastavite bližnjico"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Prekliči"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pritisnite tipko"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Kombinacija tipk je že v uporabi. Poskusite z drugo tipko."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Krmarjenje s tipkovnico"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Učenje bližnjičnih tipk"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Krmarjenje s sledilno ploščico"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 9ed8bf2..d082bfd 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Miniaplikacionet në ekranin e kyçjes"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Për të hapur një aplikacion duke përdorur një miniaplikacion, do të duhet të verifikosh që je ti. Ki parasysh gjithashtu që çdo person mund t\'i shikojë, edhe kur tableti yt është i kyçur. Disa miniaplikacione mund të mos jenë planifikuar për ekranin tënd të kyçjes dhe mund të mos jetë e sigurt t\'i shtosh këtu."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"E kuptova"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Ndërro përdorues"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menyja me tërheqje poshtë"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Të gjitha aplikacionet dhe të dhënat në këtë sesion do të fshihen."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shfaqet në krye të njoftimeve të bisedës dhe si fotografia e profilit në ekranin e kyçjes, shfaqet si flluskë dhe ndërpret modalitetin \"Mos shqetëso\""</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Me përparësi"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk mbështet veçoritë e bisedës"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Këto njoftime nuk mund të modifikohen."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Njoftimet e telefonatave nuk mund të modifikohen."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ky grup njoftimesh nuk mund të konfigurohet këtu"</string>
@@ -1418,7 +1424,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Qasshmëria"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Shkurtoret e tastierës"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizo shkurtoret e tastierës"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Shtyp tastin për të caktuar shkurtoren"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Kërko për shkurtoret"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Asnjë rezultat kërkimi"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona e palosjes"</string>
@@ -1431,9 +1442,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Doreza e zvarritjes"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Cilësimet e tastierës"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Cakto shkurtoren"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Anulo"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Shtyp tastin"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Kombinimi i tasteve është tashmë në përdorim. Provo një tast tjetër."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigo duke përdorur tastierën tënde"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Mëso shkurtoret e tastierës"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigo duke përdorur bllokun me prekje"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 102c452..71fd8879 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Виџети за закључани екран"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Да бисте отворили апликацију која користи виџет, треба да потврдите да сте то ви. Имајте у виду да свако може да га види, чак и када је таблет закључан. Неки виџети можда нису намењени за закључани екран и можда није безбедно да их тамо додате."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Важи"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Замени корисника"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"падајући мени"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Све апликације и подаци у овој сесији ће бити избрисани."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Приказује се у врху обавештења о конверзацијама и као слика профила на закључаном екрану, појављује се као облачић, прекида режим Не узнемиравај"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Приоритетно"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не подржава функције конверзације"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ова обавештења не могу да се мењају."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Обавештења о позивима не могу да се мењају."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ова група обавештења не може да се конфигурише овде"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Користите мањи број знакова од <xliff:g id="LENGTH">%1$d</xliff:g>"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Број верзије"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Број верзије је копиран у привремену меморију."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"копирајте у привремену меморију."</string>
     <string name="basic_status" msgid="2315371112182658176">"Отворите конверзацију"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Виџети за конверзацију"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Додирните конверзацију да бисте је додали на почетни екран"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"За већу резолуцију обрните телефон"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Уређај на преклоп се отвара"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Уређај на преклоп се обрће"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Предњи екран је укључен"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"затворено"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"отворено"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Приступачност"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Тастерске пречице"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Прилагодите тастерске пречице"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Притисните тастер да бисте доделили пречицу"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Претражите пречице"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Нема резултата претраге"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за скупљање"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Маркер за превлачење"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Подешавања тастатуре"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Подеси пречицу"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Откажи"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Притисните тастер"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Комбинација тастера се већ користи. Пробајте са другим тастером."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Крећите се помоћу тастатуре"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Сазнајте више о тастерским пречицама"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Крећите се помоћу тачпеда"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index c2ac216..175b1d0 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgetar för låsskärm"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Du måste verifiera din identitet innan du öppnar en app med en widget. Tänk också på att alla kan se dem, även när surfplattan är låst. Vissa widgetar kanske inte är avsedda för låsskärmen och det kan vara osäkert att lägga till dem här."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Byt användare"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullgardinsmeny"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alla appar och data i denna session kommer att raderas."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Visas högst upp i konversationsaviseringarna och som profilbild på låsskärmen, visas som bubbla, åsidosätter Stör ej"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inte stöd för konversationsfunktioner"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Det går inte att ändra de här aviseringarna."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Det går inte att ändra samtalsaviseringarna."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Den här aviseringsgruppen kan inte konfigureras här"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Använd färre än <xliff:g id="LENGTH">%1$d</xliff:g> tecken"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Versionsnummer"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Versionsnumret har kopierats till urklipp."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"kopiera till urklipp."</string>
     <string name="basic_status" msgid="2315371112182658176">"Öppen konversation"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Konversationswidgetar"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Tryck på en konversation för att lägga till den på startskärmen"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Vänd telefonen för högre upplösning"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"En vikbar enhet viks upp"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"En vikbar enhet vänds"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Den främre skärmen har aktiverats"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"hopvikt"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"uppvikt"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Tillgänglighet"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Kortkommandon"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Anpassa kortkommandon"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Tryck på tangenten för att ange kortkommando"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Sökgenvägar"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Inga sökresultat"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikonen Komprimera"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Handtag"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Tangentbordsinställningar"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Ange kortkommando"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Avbryt"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tryck på tangenten"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Tangentkombinationen används redan. Testa en annan tangent."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigera med tangentbordet"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Lär dig kortkommandon"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigera med styrplattan"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 3418907..fe431b7 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Wijeti zinazoonekana kwenye skrini iliyofungwa"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Utahitaji kuthibitisha kuwa ni wewe ili ufungue programu ukitumia wijeti. Pia, kumbuka kuwa mtu yeyote anaweza kuziona, hata kishikwambi chako kikiwa kimefungwa. Huenda baadhi ya wijeti hazikukusudiwa kutumika kwenye skrini yako iliyofungwa na huenda si salama kuziweka hapa."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Nimeelewa"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Badili mtumiaji"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menyu ya kuvuta chini"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Data na programu zote katika kipindi hiki zitafutwa."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Huonyeshwa kwenye sehemu ya juu ya arifa za mazungumzo na kama picha ya wasifu kwenye skrini iliyofungwa. Huonekana kama kiputo na hukatiza kipengele cha Usinisumbue"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Kipaumbele"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> haitumii vipengele vya mazungumzo"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Arifa hizi haziwezi kubadilishwa."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Arifa za simu haziwezi kubadilishwa."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Kikundi hiki cha arifa hakiwezi kuwekewa mipangilio hapa"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Kwa ubora wa juu, geuza simu"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Kifaa kinachokunjwa kikikunjuliwa"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Kifaa kinachokunjwa kikigeuzwa"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Umewasha skrini ya mbele"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kimekunjwa"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kimefunguliwa"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Ufikivu"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Mikato ya kibodi"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Weka mapendeleo ya mikato ya kibodi"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Bonyeza kitufe ukabidhi njia ya mkato"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Njia mkato za kutafutia"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Hamna matokeo ya utafutaji"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Kunja aikoni"</string>
@@ -1431,15 +1441,22 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Aikoni ya buruta"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Mipangilio ya Kibodi"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Weka njia ya mkato"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Acha"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Bonyeza kitufe"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Tayari unatumia mchanganyiko huu wa vitufe. Jatibu kitufe kingine."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Kusogeza kwa kutumia kibodi yako"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Fahamu kuhusu mikato ya kibodi"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Kusogeza kwa kutumia padi yako ya kugusa"</string>
     <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Fahamu miguso ya padi ya kugusa"</string>
     <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Kusogeza kwa kutumia kibodi na padi yako ya kugusa"</string>
-    <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Jifunze kuhusu miguso ya padi ya kugusa, mikato ya kibodi na mengineyo"</string>
+    <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Fahamu kuhusu miguso ya padi ya kugusa, mikato ya kibodi na mengineyo"</string>
     <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Rudi nyuma"</string>
     <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Nenda kwenye ukurasa wa mwanzo"</string>
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Angalia programu za hivi majuzi"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 99c912c..6d03b79 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"பூட்டுத் திரை விட்ஜெட்கள்"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"விட்ஜெட்டைப் பயன்படுத்தி ஆப்ஸைத் திறக்க, அது நீங்கள்தான் என்பதை உறுதிசெய்ய வேண்டும். அத்துடன், உங்கள் டேப்லெட் பூட்டப்பட்டிருந்தாலும்கூட அவற்றை யார் வேண்டுமானாலும் பார்க்கலாம் என்பதை நினைவில்கொள்ளுங்கள். சில விட்ஜெட்கள் உங்கள் பூட்டுத் திரைக்காக உருவாக்கப்பட்டவை அல்ல என்பதையும் அவற்றை இங்கே சேர்ப்பது பாதுகாப்பற்றதாக இருக்கக்கூடும் என்பதையும் நினைவில்கொள்ளுங்கள்."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"சரி"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"பயனரை மாற்று"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"கீழ் இழுக்கும் மெனு"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"இந்த அமர்வின் எல்லா ஆப்ஸும் தரவும் நீக்கப்படும்."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"உரையாடல் அறிவிப்புகளின் மேற்பகுதியில் காட்டப்படும், திரை பூட்டப்பட்டிருக்கும்போது சுயவிவரப் படமாகக் காட்டப்படும், குமிழாகத் தோன்றும், தொந்தரவு செய்ய வேண்டாம் அம்சம் இயக்கப்பட்டிருக்கும்போதும் காட்டப்படும்"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"முன்னுரிமை"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"உரையாடல் அம்சங்களை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காது"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"இந்த அறிவிப்புகளை மாற்ற இயலாது."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"அழைப்பு அறிவிப்புகளை மாற்ற முடியாது."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"இந்த அறிவுப்புக் குழுக்களை இங்கே உள்ளமைக்க இயலாது"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"உயர் தெளிவுத்திறனுக்கு, மொபைலை ஃபிளிப் செய்யுங்கள்"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"மடக்கத்தக்க சாதனம் திறக்கப்படுகிறது"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"மடக்கத்தக்க சாதனம் ஃபிளிப் செய்யப்பட்டு திருப்பப்படுகிறது"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"முன்பக்கத் திரை இயக்கப்பட்டுள்ளது"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"மடக்கப்பட்டது"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"விரிக்கப்பட்டது"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"மாற்றுத்திறன் வசதி"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"கீபோர்டு ஷார்ட்கட்கள்"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"கீபோர்டு ஷார்ட்கட்களைப் பிரத்தியேகப்படுத்துதல்"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"ஷார்ட்கட்டை அமைக்க பட்டனை அழுத்துங்கள்"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ஷார்ட்கட்களைத் தேடுக"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"தேடல் முடிவுகள் இல்லை"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"சுருக்குவதற்கான ஐகான்"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"இழுப்பதற்கான ஹேண்டில்"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"கீபோர்டு அமைப்புகள்"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ஷார்ட்கட்டை அமையுங்கள்"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ரத்துசெய்"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"பட்டனை அழுத்துங்கள்"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"பட்டன் சேர்க்கை ஏற்கெனவே பயன்பாட்டில் உள்ளது. வேறொரு பட்டனைப் பயன்படுத்திப் பார்க்கவும்."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"கீபோர்டைப் பயன்படுத்திச் செல்லுதல்"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"கீபோர்டு ஷார்ட்கட்கள் குறித்துத் தெரிந்துகொள்ளுங்கள்"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"டச்பேடைப் பயன்படுத்திச் செல்லுதல்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 5a08823..cfe5101 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"లాక్ స్క్రీన్ విడ్జెట్‌లు"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"విడ్జెట్‌ను ఉపయోగించి యాప్‌ను తెరవడానికి, ఇది మీరేనని వెరిఫై చేయాల్సి ఉంటుంది. అలాగే, మీ టాబ్లెట్ లాక్ చేసి ఉన్నప్పటికీ, ఎవరైనా వాటిని చూడగలరని గుర్తుంచుకోండి. కొన్ని విడ్జెట్‌లు మీ లాక్ స్క్రీన్‌కు తగినవి కాకపోవచ్చు, వాటిని ఇక్కడ జోడించడం సురక్షితం కాకపోవచ్చు."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"అర్థమైంది"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"వినియోగదారుని మార్చు"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"పుల్‌డౌన్ మెనూ"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ఈ సెషన్‌లోని అన్ని యాప్‌లు మరియు డేటా తొలగించబడతాయి."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"సంభాషణ నోటిఫికేషన్‌ల ఎగువున, లాక్ స్క్రీన్‌లో ప్రొఫైల్ ఫోటో‌గా చూపిస్తుంది, బబుల్‌గా కనిపిస్తుంది, \'అంతరాయం కలిగించవద్దు\'ను అంతరాయం కలిగిస్తుంది"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"ప్రాధాన్యత"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> సంభాషణ ఫీచర్‌లను సపోర్ట్ చేయదు"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"ఈ నోటిఫికేషన్‌లను ఎడిట్ చేయడం వీలుపడదు."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"కాల్ నోటిఫికేషన్‌లను ఎడిట్ చేయడం సాధ్యం కాదు."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"ఈ నోటిఫికేషన్‌ల గ్రూప్‌ను ఇక్కడ కాన్ఫిగర్ చేయలేము"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"అధిక రిజల్యూషన్ కోసం, ఫోన్‌ను తిప్పండి"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"మడవగల పరికరం విప్పబడుతోంది"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"మడవగల పరికరం చుట్టూ తిప్పబడుతోంది"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ముందు వైపు స్క్రీన్ ఆన్ అయింది"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"మడిచే సదుపాయం గల పరికరం"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"మడిచే సదుపాయం లేని పరికరం"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"యాక్సెసిబిలిటీ"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"కీబోర్డ్ షార్ట్‌కట్‌లు"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"కీబోర్డ్ షార్ట్‌కట్‌లను అనుకూలంగా మార్చండి"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"షార్ట్‌కట్‌ను కేటాయించడానికి కీని నొక్కండి"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"షార్ట్‌కట్‌లను వెతకండి"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"సెర్చ్ ఫలితాలు ఏవీ లేవు"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"కుదించండి చిహ్నం"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"లాగే హ్యాండిల్"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"కీబోర్డ్ సెట్టింగ్‌లు"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"షార్ట్‌కట్‌ను సెట్ చేయండి"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"రద్దు చేయండి"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"కీని నొక్కండి"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"కీ కాంబినేషన్ ఇప్పటికే వినియోగంలో ఉంది. వేరొక కీని ట్రై చేయండి."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"మీ కీబోర్డ్ ఉపయోగించి నావిగేట్ చేయండి"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"కీబోర్డ్ షార్ట్‌కట్‌ల గురించి తెలుసుకోండి"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"మీ టచ్‌ప్యాడ్‌ను ఉపయోగించి నావిగేట్ చేయండి"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 816514a..d2b7012 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"วิดเจ็ตในหน้าจอล็อก"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"หากต้องการเปิดแอปโดยใช้วิดเจ็ต คุณจะต้องยืนยันตัวตนของคุณ นอกจากนี้ โปรดทราบว่าผู้อื่นจะดูวิดเจ็ตเหล่านี้ได้แม้ว่าแท็บเล็ตจะล็อกอยู่ก็ตาม วิดเจ็ตบางอย่างอาจไม่ได้มีไว้สำหรับหน้าจอล็อกของคุณ และอาจไม่ปลอดภัยที่จะเพิ่มที่นี่"</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"รับทราบ"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"สลับผู้ใช้"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"เมนูแบบเลื่อนลง"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ระบบจะลบแอปและข้อมูลทั้งหมดในเซสชันนี้"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"แสดงที่ด้านบนของการแจ้งเตือนการสนทนาและเป็นรูปโปรไฟล์บนหน้าจอล็อก ปรากฏเป็นบับเบิล แสดงในโหมดห้ามรบกวน"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"สำคัญ"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่รองรับฟีเจอร์การสนทนา"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"แก้ไขการแจ้งเตือนเหล่านี้ไม่ได้"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"แก้ไขการแจ้งเตือนสายเรียกเข้าไม่ได้"</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"การแจ้งเตือนกลุ่มนี้กำหนดค่าที่นี่ไม่ได้"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"ใช้อักขระไม่เกิน <xliff:g id="LENGTH">%1$d</xliff:g> ตัว"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"หมายเลขบิลด์"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"คัดลอกหมายเลขบิลด์ไปยังคลิปบอร์ดแล้ว"</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"คัดลอกไปยังคลิปบอร์ด"</string>
     <string name="basic_status" msgid="2315371112182658176">"เปิดการสนทนา"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"วิดเจ็ตการสนทนา"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"แตะการสนทนาเพื่อเพิ่มไปยังหน้าจอหลัก"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"พลิกด้านโทรศัพท์เพื่อให้ได้ภาพที่มีความละเอียดมากขึ้น"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"อุปกรณ์ที่พับได้กำลังกางออก"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"อุปกรณ์ที่พับได้กำลังพลิกไปมา"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"เปิดหน้าจอด้านหน้าแล้ว"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"พับ"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"กางออก"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"การช่วยเหลือพิเศษ"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"แป้นพิมพ์ลัด"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"ปรับแต่งแป้นพิมพ์ลัด"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"กดแป้นเพื่อกำหนดแป้นพิมพ์ลัด"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ค้นหาแป้นพิมพ์ลัด"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ไม่พบผลการค้นหา"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ไอคอนยุบ"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"แฮนเดิลการลาก"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"การตั้งค่าแป้นพิมพ์"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ตั้งค่าแป้นพิมพ์ลัด"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ยกเลิก"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"กดแป้น"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"มีการใช้แป้นที่กดร่วมกันนี้แล้ว โปรดลองใช้แป้นอื่น"</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ไปยังส่วนต่างๆ โดยใช้แป้นพิมพ์"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ดูข้อมูลเกี่ยวกับแป้นพิมพ์ลัด"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ไปยังส่วนต่างๆ โดยใช้ทัชแพด"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 3845fcd..132bb62 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Mga widget ng lock screen"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para magbukas ng app gamit ang isang widget, kakailanganin mong i-verify na ikaw iyan. Bukod pa rito, tandaang puwedeng tingnan ng kahit na sino ang mga ito, kahit na naka-lock ang iyong tablet. Posibleng hindi para sa iyong lock screen ang ilang widget at posibleng hindi ligtas ang mga ito na idagdag dito."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Magpalit ng user"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ide-delete ang lahat ng app at data sa session na ito."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Makikita sa itaas ng mga notification ng pag-uusap at bilang larawan sa profile sa lock screen, lumalabas bilang bubble, naaabala ang Huwag Istorbohin"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Priyoridad"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"Hindi sinusuportahan ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang mga feature ng pag-uusap"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Hindi puwedeng baguhin ang mga notification na ito."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Hindi mabago ang mga notification ng tawag."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Hindi mako-configure dito ang pangkat na ito ng mga notification"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Gumamit ng mas kaunti sa <xliff:g id="LENGTH">%1$d</xliff:g> (na) character"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero ng build"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Nakopya sa clipboard ang numero ng build."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"kopyahin sa clipboard."</string>
     <string name="basic_status" msgid="2315371112182658176">"Buksan ang pag-uusap"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Mga widget ng pag-uusap"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Mag-tap sa isang pag-uusap para idagdag ito sa iyong Home screen"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Para sa mas mataas na resolution, i-flip ang telepono"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Ina-unfold na foldable na device"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Fini-flip na foldable na device"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Na-on ang screen sa harap"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"naka-fold"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"hindi naka-fold"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibility"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Mga keyboard shortcut"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"I-customize ang mga keyboard shortcut"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Pindutin ang key para magtalaga ng shortcut"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Mga shortcut ng paghahanap"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Walang resulta ng paghahanap"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"I-collapse ang icon"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Handle sa pag-drag"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Mga Setting ng Keyboard"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Magtakda ng shortcut"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Kanselahin"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pindutin ang key"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Ginagamit na ang kumbinasyon ng key. Sumubok ng ibang key."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Mag-navigate gamit ang iyong keyboard"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Matuto ng mga keyboard shortcut"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Mag-navigate gamit ang iyong touchpad"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 45d8b46..afdc9a0 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -113,7 +113,7 @@
     <string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Bir uygulamayı kaydet"</string>
     <string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Tüm ekranı kaydet"</string>
     <string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="3754611651558838691">"Tüm ekranı kaydet: %s"</string>
-    <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Tüm ekranınızı kaydettiğinizde ekranınızda gösterilen her şey kaydedilir. Bu nedenle şifre, ödeme ayrıntıları, mesaj, fotoğraf, ses ve video gibi öğeler konusunda dikkatli olun."</string>
+    <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Ekranın tamamını kaydederken ekranınızda gösterilen her şey kaydedilir. Bu nedenle şifre, ödeme ayrıntıları, mesaj, fotoğraf, ses ve video gibi öğeler konusunda dikkatli olun."</string>
     <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Bir uygulamayı kaydettiğinizde o uygulamada gösterilen veya oynatılan her şey kaydedilir. Bu nedenle şifre, ödeme ayrıntıları, mesaj, fotoğraf, ses ve video gibi öğeler konusunda dikkatli olun."</string>
     <string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Ekranı kaydet"</string>
     <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Kaydedilecek uygulamayı seçin"</string>
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Kilit ekranı widget\'ları"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Widget kullanarak bir uygulamayı açmak için kimliğinizi doğrulamanız gerekir. Ayrıca, tabletiniz kilitliyken bile widget\'ların herkes tarafından görüntülenebileceğini unutmayın. Bazı widget\'lar kilit ekranınız için tasarlanmamış olabileceğinden buraya eklenmeleri güvenli olmayabilir."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Anladım"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kullanıcı değiştirme"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"açılır menü"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu oturumdaki tüm uygulamalar ve veriler silinecek."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Görüşme bildirimlerinin üstünde ve kilit ekranında profil resmi olarak gösterilir, baloncuk olarak görünür, Rahatsız Etmeyin\'i kesintiye uğratır"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Öncelikli"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>, sohbet özelliklerini desteklemiyor"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirimler değiştirilemez."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Arama bildirimleri değiştirilemez."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Bu bildirim grubu burada yapılandırılamaz"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Daha yüksek çözünürlük için telefonu çevirin"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Katlanabilir cihaz açılıyor"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Katlanabilir cihaz döndürülüyor"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Ön ekran açıldı"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"katlanmış"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"katlanmamış"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Erişilebilirlik"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Klavye kısayolları"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Klavye kısayollarını özelleştirin"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Kısayol atamak için tuşa basın"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Arama kısayolları"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Arama sonucu yok"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Daralt simgesi"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Sürükleme tutamacı"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Klavye Ayarları"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Kısayol ayarla"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"İptal"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tuşa basın"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Tuş kombinasyonu zaten kullanılıyor. Başka bir tuş deneyin."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Klavyenizi kullanarak gezinin"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Klavye kısayollarını öğrenin"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Dokunmatik alanınızı kullanarak gezinin"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 4c4c80e..17d2081 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Віджети для заблокованого екрана"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Щоб відкрити додаток за допомогою віджета, вам потрібно буде підтвердити особу. Пам’ятайте також, що бачити віджети можуть усі, навіть коли планшет заблоковано. Можливо, деякі віджети не призначені для заблокованого екрана, і додавати їх на нього може бути небезпечно."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Змінити користувача"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"спадне меню"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усі додатки й дані з цього сеансу буде видалено."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"З’являється вгорі сповіщень про розмови і як зображення профілю на заблокованому екрані, відображається як спливаючий чат, перериває режим \"Не турбувати\""</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Пріоритет"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не підтримує функції розмов"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ці сповіщення не можна змінити."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Сповіщення про виклик не можна змінити."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Цю групу сповіщень не можна налаштувати тут"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Для вищої роздільної здатності переверніть телефон"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Розкладний пристрій у розкладеному стані"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Розкладний пристрій обертається"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Передній екран увімкнено"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"складений"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"розкладений"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Доступність"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Комбінації клавіш"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Налаштуйте комбінації клавіш"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Натисніть клавішу, щоб призначити комбінацію клавіш"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Комбінації клавіш для пошуку"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Нічого не знайдено"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок згортання"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Маркер переміщення"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Налаштування клавіатури"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Налаштувати комбінацію клавіш"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Скасувати"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Натисніть клавішу"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Комбінація клавіш уже використовується. Спробуйте іншу клавішу."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Навігація за допомогою клавіатури"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Дізнайтеся більше про комбінації клавіш"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Навігація за допомогою сенсорної панелі"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 109f43e..f9d4141 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"مقفل اسکرین کے ویجیٹس"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ویجیٹ کے ذریعے ایپ کھولنے کے لیے آپ کو تصدیق کرنی ہوگی کہ یہ آپ ہی ہیں۔ نیز، ذہن میں رکھیں کہ کوئی بھی انہیں دیکھ سکتا ہے، یہاں تک کہ جب آپ کا ٹیبلیٹ مقفل ہو۔ ہو سکتا ہے کچھ ویجٹس آپ کی لاک اسکرین کے لیے نہ بنائے گئے ہوں اور یہاں شامل کرنا غیر محفوظ ہو سکتا ہے۔"</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"سمجھ آ گئی"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"صارف سوئچ کریں"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"پل ڈاؤن مینیو"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"اس سیشن میں موجود سبھی ایپس اور ڈیٹا کو حذف کر دیا جائے گا۔"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"یہ گفتگو کی اطلاعات کے اوپری حصّے پر اور مقفل اسکرین پر پروفائل کی تصویر کے بطور دکھائی دیتا ہے، بلبلے کے بطور ظاہر ہوتا ہے، \'ڈسٹرب نہ کریں\' میں مداخلت کرتا ہے"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"ترجیح"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ گفتگو کی خصوصیات کو سپورٹ نہیں کرتی ہے"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"ان اطلاعات کی ترمیم نہیں کی جا سکتی۔"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"کال کی اطلاعات میں ترمیم نہیں کی جا سکتی۔"</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"اطلاعات کے اس گروپ کو یہاں کنفیگر نہیں کیا جا سکتا"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"زیادہ ریزولوشن کے لیے، فون پلٹائیں"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"فولڈ ہونے والے آلے کو کھولا جا رہا ہے"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"فولڈ ہونے والے آلے کو گھمایا جا رہا ہے"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"فرنٹ اسکرین آن ہے"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"فولڈ کردہ"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"اَن فولڈ کردہ"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ایکسیسبیلٹی"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"کی بورڈ شارٹ کٹس"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"کی بورڈ شارٹ کٹس کو حسب ضرورت بنائیں"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"شارٹ کٹ تفویض کرنے کے لیے کلید کو دبائیں"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"تلاش کے شارٹ کٹس"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"تلاش کا کوئی نتیجہ نہیں ہے"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"آئیکن سکیڑیں"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"گھسیٹنے کا ہینڈل"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"کی بورڈ کی ترتیبات"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"شارٹ کٹ سیٹ کریں"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"منسوخ کریں"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"کلید کو دبائیں"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"کلیدی مجموعہ پہلے سے استعمال میں ہے۔ دوسری کلید آزمائیں۔"</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"اپنے کی بورڈ کا استعمال کر کے نیویگیٹ کریں"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"کی بورڈ شارٹ کٹس جانیں"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"اپنے ٹچ پیڈ کا استعمال کر کے نیویگیٹ کریں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 1c27a00..4f97000 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Ekran qulfi vidjetlari"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Ilovani vidjet orqali ochish uchun shaxsingizni tasdiqlashingiz kerak. Shuningdek, planshet qulflanganda ham bu axborotlar hammaga koʻrinishini unutmang. Ayrim vidjetlar ekran qulfiga moslanmagan va ularni bu yerda chiqarish xavfli boʻlishi mumkin."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Foydalanuvchini almashtirish"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"tortib tushiriladigan menyu"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ushbu seansdagi barcha ilovalar va ma’lumotlar o‘chirib tashlanadi."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Suhbat bildirishnomalari tepasida va ekran qulfida profil rasmi sifatida chiqariladi, bulutcha sifatida chiqadi, Bezovta qilinmasin rejimini bekor qiladi"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Muhim"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasida suhbat funksiyalari ishlamaydi"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirishnomalarni tahrirlash imkonsiz."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Chaqiruv bildirishnomalarini tahrirlash imkonsiz."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ushbu bildirishnomalar guruhi bu yerda sozlanmaydi"</string>
@@ -1220,8 +1226,7 @@
     <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Kiritiladigan belgilar <xliff:g id="LENGTH">%1$d</xliff:g> tadan oshmasin"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Nashr raqami"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Nashr raqami vaqtinchalik xotiraga nusxalandi."</string>
-    <!-- no translation found for copy_to_clipboard_a11y_action (4312789069718446749) -->
-    <skip />
+    <string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"vaqtincha xotiraga nusxalash"</string>
     <string name="basic_status" msgid="2315371112182658176">"Suhbatni ochish"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Suhbat vidjetlari"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Bosh ekranga chiqariladigan suhbat ustiga bosing"</string>
@@ -1357,8 +1362,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Yuqori aniqlik uchun telefonni aylantiring"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Buklanadigan qurilma ochilmoqda"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Buklanadigan qurilma aylantirilmoqda"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Old ekran yoqildi"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"buklangan"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"buklanmagan"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1422,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Qulayliklar"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Tezkor tugmalar"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Tezkor tugmalarni moslash"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Tezkor tugma sozlash uchun tugmani bosing"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Tezkor tugmalar qidiruvi"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Hech narsa topilmadi"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Yigʻish belgisi"</string>
@@ -1431,9 +1440,15 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Surish dastagi"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Klaviatura sozlamalari"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Tezkor tugma sozlash"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Bekor qilish"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tugmani bosing"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Bu tugmalar birikmasi band. Boshqasini ishlating."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Klaviatura yordamida kezing"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Tezkor tugmalar haqida"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Sensorli panel yordamida kezing"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index d8e3bc0..417f494 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Tiện ích trên màn hình khoá"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Để dùng tiện ích mở một ứng dụng, bạn cần xác minh danh tính của mình. Ngoài ra, hãy lưu ý rằng bất kỳ ai cũng có thể xem các tiện ích này, ngay cả khi máy tính bảng của bạn được khoá. Một số tiện ích có thể không dành cho màn hình khoá và không an toàn khi thêm vào đây."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Tôi hiểu"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Chuyển đổi người dùng"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"trình đơn kéo xuống"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tất cả ứng dụng và dữ liệu trong phiên này sẽ bị xóa."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Hiện ở đầu phần thông báo cuộc trò chuyện và ở dạng ảnh hồ sơ trên màn hình khóa, xuất hiện ở dạng bong bóng, làm gián đoạn chế độ Không làm phiền"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Mức độ ưu tiên"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> không hỗ trợ các tính năng trò chuyện"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Không thể sửa đổi các thông báo này."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Không thể sửa đổi các thông báo cuộc gọi."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Không thể định cấu hình nhóm thông báo này tại đây"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Để có độ phân giải cao hơn, hãy lật điện thoại"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Thiết bị có thể gập lại đang được mở ra"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Thiết bị có thể gập lại đang được lật ngược"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Đã bật màn hình trước"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"gập"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"mở"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Hỗ trợ tiếp cận"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Phím tắt"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Tuỳ chỉnh phím tắt"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Nhấn phím để chỉ định phím tắt"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Tìm lối tắt"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Không có kết quả tìm kiếm nào"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Biểu tượng Thu gọn"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Nút kéo"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Cài đặt bàn phím"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Đặt phím tắt"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Huỷ"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Nhấn phím"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Tổ hợp phím đã được sử dụng. Hãy thử một phím khác."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Di chuyển bằng bàn phím"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Tìm hiểu về phím tắt"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Di chuyển bằng bàn di chuột"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index d9a974a..3b72bd5 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -113,7 +113,7 @@
     <string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"录制单个应用"</string>
     <string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"录制整个屏幕"</string>
     <string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="3754611651558838691">"全屏录制:%s"</string>
-    <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"录制整个屏幕时,屏幕上显示的所有内容均会被录制。因此,请务必小心操作,谨防泄露密码、付款信息、消息、照片、音频、视频等。"</string>
+    <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"录制整个屏幕时,屏幕上显示的所有内容均会被录制。因此,请务必小心操作,谨防泄露密码、付款详情、消息、照片、音频、视频等敏感信息。"</string>
     <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"录制单个应用时,该应用中显示或播放的所有内容均会被录制。因此,请务必小心操作,谨防泄露密码、付款信息、消息、照片、音频、视频等。"</string>
     <string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"录制屏幕"</string>
     <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"选择要录制的应用"</string>
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"锁屏微件"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"若要使用微件打开应用,您需要验证是您本人在操作。另外请注意,任何人都可以查看此类微件,即使您的平板电脑已锁定。有些微件可能不适合显示在锁定的屏幕中,因此添加到这里可能不安全。"</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"知道了"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切换用户"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"下拉菜单"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"此会话中的所有应用和数据都将被删除。"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"以气泡形式显示在对话通知顶部(屏幕锁定时显示为个人资料照片),并且会中断勿扰模式"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"优先"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>不支持对话功能"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"无法修改这些通知。"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"无法修改来电通知。"</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"您无法在此处配置这组通知"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"若要获得更高的分辨率,请翻转手机"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"正在展开可折叠设备"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"正在翻转可折叠设备"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"前屏已开启"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"折叠状态"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"展开状态"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"无障碍功能"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"键盘快捷键"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"自定义键盘快捷键"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"按下按键即可指定快捷键"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜索快捷键"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"无搜索结果"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收起图标"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"拖动手柄"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"键盘设置"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"设置快捷键"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"取消"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"按下按键"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"按键组合已被使用,请尝试使用其他按键。"</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"使用键盘导航"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"了解键盘快捷键"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"使用触控板导航"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 443b855..aca9e68 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"上鎖畫面小工具"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"如要使用小工具開啟應用程式,系統會要求你驗證身分。請注意,所有人都能查看小工具,即使平板電腦已鎖定亦然。部分小工具可能不適用於上鎖畫面,新增至這裡可能會有安全疑慮。"</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"知道了"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"下拉式選單"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會被刪除。"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"以對話氣泡形式顯示在對話通知頂部 (在上鎖畫面會顯示為個人檔案相片),並會中斷「請勿打擾」模式"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"優先"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話功能"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"無法修改通話通知。"</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"無法在此設定這組通知"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"如要提高解像度,請切換至手機後置鏡頭"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"正在展開折疊式裝置"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"正在翻轉折疊式裝置"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"正面螢幕已開啟"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"已摺疊"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"已打開"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"無障礙功能"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"鍵盤快速鍵"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"自訂鍵盤快速鍵"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"按鍵即可指派快速鍵"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜尋快速鍵"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"沒有相符的搜尋結果"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收合圖示"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"拖曳控點"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"鍵盤設定"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"設定快速鍵"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"取消"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"按鍵"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"此按鍵組合已在使用,請改用其他按鍵。"</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"使用鍵盤導覽"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"瞭解鍵盤快速鍵"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"使用觸控板導覽"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 4b84f25..506ed57 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"螢幕鎖定小工具"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"如要使用小工具開啟應用程式,需先驗證身分。請留意,即使平板電腦已鎖定,所有人都還是能查看小工具。某些小工具可能不適用於螢幕鎖定畫面,新增到此可能會有安全疑慮。"</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"我知道了"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"下拉式選單"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會刪除。"</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"以對話框的形式顯示在對話通知頂端 (螢幕鎖定時會顯示為個人資料相片),並會中斷「零打擾」模式"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"優先"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話功能"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"無法修改來電通知。"</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"無法在這裡設定這個通知群組"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"如要提高解析度,請切換至手機後置鏡頭"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"正在展開的折疊式裝置"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"正在翻轉折疊式裝置"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"正面螢幕已開啟"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"已摺疊"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"已展開"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"無障礙"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"鍵盤快速鍵"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"自訂鍵盤快速鍵"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"按下按鍵即可指派快速鍵"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜尋快速鍵"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"找不到相符的搜尋結果"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收合圖示"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"拖曳控點"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"鍵盤設定"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"設定快速鍵"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"取消"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"按下按鍵"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"這個按鍵組合已在使用中,請改用其他按鍵。"</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"使用鍵盤操作"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"學習鍵盤快速鍵"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"使用觸控板操作"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 4afb67d..1a17fcc 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -528,6 +528,10 @@
     <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Amawijethi wesikrini esikhiyiwe"</string>
     <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Ukuze uvule i-app usebenzisa iwijethi, uzodinga ukuqinisekisa ukuthi nguwe. Futhi, khumbula ukuthi noma ubani angakwazi ukuzibuka, nanoma ithebhulethi yakho ikhiyiwe. Amanye amawijethi kungenzeka abengahloselwe ukukhiya isikrini sakho futhi kungenzeka awaphephile ukuthi angafakwa lapha."</string>
     <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ngiyezwa"</string>
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_label (1461611028615752141) -->
+    <skip />
+    <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (511359420883794513) -->
+    <skip />
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Shintsha umsebenzisi"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"imenyu yokudonsela phansi"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wonke ama-app nedatha kulesi sikhathi azosuswa."</string>
@@ -780,6 +784,8 @@
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Ivela phezu kwezaziso zengxoxo futhi njengesithombe sephrofayela esikrinini sokukhiya, ivela njengebhamuza, ukuphazamisa okuthi Ungaphazamisi"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Okubalulekile"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayisekeli izici zengxoxo"</string>
+    <!-- no translation found for notification_guts_bundle_feedback (5393570876655201459) -->
+    <skip />
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Lezi zaziso azikwazi ukushintshwa."</string>
     <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Izaziso zekholi azikwazi ukushintshwa."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Leli qembu lezaziso alikwazi ukulungiselelwa lapha"</string>
@@ -1357,8 +1363,7 @@
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Ukuze uthole ukulungiswa okuphezulu, phendula ifoni"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Idivayisi egoqekayo iyembulwa"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Idivayisi egoqekayo iphendulwa nxazonke"</string>
-    <!-- no translation found for rear_display_unfolded_front_screen_on (5946436677205643170) -->
-    <skip />
+    <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Isikrini sangaphambili sivuliwe"</string>
     <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kugoqiwe"</string>
     <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kuvuliwe"</string>
     <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1418,7 +1423,12 @@
     <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Ukufinyeleleka"</string>
     <string name="shortcut_helper_title" msgid="8567500639300970049">"Izinqamuleli zekhibhodi"</string>
     <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Hlela izinqamuleli zekhibhodi ngendlela oyifisayo"</string>
-    <string name="shortcut_helper_customize_mode_sub_title" msgid="2479732335876820286">"Cindezela ukhiye ukuze unikeze isinqamuleli"</string>
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_dialog_title (7106420484940737208) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_add_shortcut_description (6866025005347407696) -->
+    <skip />
+    <!-- no translation found for shortcut_customize_mode_remove_shortcut_description (6851287900585057128) -->
+    <skip />
     <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Sesha izinqamuleli"</string>
     <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ayikho imiphumela yosesho"</string>
     <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Goqa isithonjana"</string>
@@ -1431,9 +1441,16 @@
     <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Hudula isibambi"</string>
     <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Amasethingi Ekhibhodi"</string>
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Setha isinqamuleli"</string>
+    <!-- no translation found for shortcut_helper_customize_dialog_remove_button_label (6546386970440176552) -->
+    <skip />
     <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Khansela"</string>
     <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Cindezela ukhiye"</string>
-    <string name="shortcut_helper_customize_dialog_error_message" msgid="5954264095841845768">"Inhlanganisela yokhiye isiyasetshenziswa kakade. Zama omunye ukhiye."</string>
+    <!-- no translation found for shortcut_customizer_key_combination_in_use_error_message (7693234470526626327) -->
+    <skip />
+    <!-- no translation found for shortcut_customizer_generic_error_message (3128454624049722741) -->
+    <skip />
+    <!-- no translation found for shortcut_helper_plus_symbol (4534843157353732011) -->
+    <skip />
     <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Funa usebenzisa ikhibhodi yakho"</string>
     <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Funda izinqamuleli zamakhibhodi"</string>
     <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Funa usebenzisa iphedi yokuthinta"</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 411f36b..478050b 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -236,6 +236,9 @@
     <!-- The size of a bluetooth indicator icon that displays next to the RSSI status icon. -->
     <dimen name="status_bar_connected_device_bt_indicator_size">17dp</dimen>
 
+    <!-- Height of a small notification in the status bar (2025 redesign version) -->
+    <dimen name="notification_2025_min_height">@*android:dimen/notification_2025_min_height</dimen>
+
     <!-- Height of a small notification in the status bar-->
     <dimen name="notification_min_height">@*android:dimen/notification_min_height</dimen>
 
@@ -1995,12 +1998,16 @@
     <dimen name="backlight_indicator_step_large_radius">28dp</dimen>
 
     <!-- Touchpad gestures tutorial-->
-    <!-- This value is in unit of dp/ms
+    <!-- This value is in dp/ms.
         TriggerSwipeUpTouchTracker (which is base for gesture tutorial implementation) uses value
         of 0.5dp but from manual testing it's too high and doesn't really feel like it's forcing
         slowing down. Also for tutorial it should be fine to lean to the side of being more strict
         rather than not strict enough and not teaching user the proper gesture as a result.-->
     <dimen name="touchpad_recent_apps_gesture_velocity_threshold">0.05dp</dimen>
+    <!-- This value is in dp/ms.
+        As above, it's not tied to system-wide value (defined in launcher's
+        quickstep_fling_threshold_speed) because for tutorial it's fine to be more strict. -->
+    <dimen name="touchpad_home_gesture_velocity_threshold">0.5dp</dimen>
     <!-- Normal gesture threshold is system_gestures_distance_threshold but for tutorial we can
          exaggerate gesture, which also works much better with live tracking -->
     <dimen name="touchpad_tutorial_gestures_distance_threshold">48dp</dimen>
@@ -2086,7 +2093,7 @@
     <dimen name="volume_dialog_floating_sliders_vertical_padding">10dp</dimen>
     <dimen name="volume_dialog_floating_sliders_vertical_padding_negative">-10dp</dimen>
     <dimen name="volume_dialog_floating_sliders_horizontal_padding">4dp</dimen>
-    <dimen name="volume_dialog_button_size">48dp</dimen>
+    <dimen name="volume_dialog_button_size">40dp</dimen>
     <dimen name="volume_dialog_slider_width">52dp</dimen>
     <dimen name="volume_dialog_slider_height">254dp</dimen>
 
@@ -2094,7 +2101,7 @@
 
     <dimen name="volume_dialog_background_square_corner_radius">12dp</dimen>
 
-    <dimen name="volume_dialog_ringer_drawer_button_size">40dp</dimen>
+    <dimen name="volume_dialog_ringer_drawer_button_size">@dimen/volume_dialog_button_size</dimen>
     <dimen name="volume_dialog_ringer_drawer_button_icon_radius">10dp</dimen>
     <dimen name="volume_dialog_ringer_selected_button_background_radius">20dp</dimen>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 372f6a5..4bf67a1 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -753,7 +753,7 @@
     <!-- QuickSettings: Bluetooth dialog device in audio sharing default summary [CHAR LIMIT=50]-->
     <string name="quick_settings_bluetooth_device_audio_sharing">Audio Sharing</string>
     <!-- QuickSettings: Bluetooth dialog device summary for devices that are capable of audio sharing and switching to active[CHAR LIMIT=NONE]-->
-    <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active">Tap to switch or share audio</string>
+    <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active">Supports audio sharing</string>
     <!-- QuickSettings: Bluetooth dialog device saved default summary [CHAR LIMIT=NONE]-->
     <string name="quick_settings_bluetooth_device_saved">Saved</string>
     <!-- QuickSettings: Accessibility label to disconnect a device [CHAR LIMIT=NONE]-->
@@ -2287,6 +2287,14 @@
     <string name="system_multitasking_replace">During split screen: replace an app from one to another</string>
     <!-- User visible title for the keyboard shortcut that moves a focused task to a next display [CHAR LIMIT=70] -->
     <string name="system_multitasking_move_to_next_display">Move active window between displays</string>
+    <!-- User visible title for the keyboard shortcut that snaps a task to the left in desktop mode [CHAR LIMIT=70] -->
+    <string name="system_desktop_mode_snap_left_window">Move window to the left</string>
+    <!-- User visible title for the keyboard shortcut that snaps a task to the right in desktop mode [CHAR LIMIT=70] -->
+    <string name="system_desktop_mode_snap_right_window">Move window to the right</string>
+    <!-- User visible title for the keyboard shortcut that toggles between maximizing and restoring a task's previous bounds in desktop mode [CHAR LIMIT=70] -->
+    <string name="system_desktop_mode_toggle_maximize_window">Maximize window</string>
+    <!-- User visible title for the keyboard shortcut that minimizes a task in desktop mode [CHAR LIMIT=70] -->
+    <string name="system_desktop_mode_minimize_window">Minimize window</string>
 
     <!-- User visible title for the input keyboard shortcuts list. [CHAR LIMIT=70] -->
     <string name="keyboard_shortcut_group_input">Input</string>
@@ -3760,11 +3768,20 @@
          is a component that shows the user which keyboard shortcuts they can use.
          [CHAR LIMIT=NONE] -->
     <string name="shortcut_helper_customize_mode_title">Customize keyboard shortcuts</string>
+    <!-- Title at the top of the keyboard shortcut helper remove shortcut dialog.
+         The helper is a component that shows the user which keyboard shortcuts they can use. Also
+         allows the user to add/remove custom shortcuts.[CHAR LIMIT=NONE] -->
+    <string name="shortcut_customize_mode_remove_shortcut_dialog_title">Remove shortcut?</string>
     <!-- Sub title at the top of the keyboard shortcut helper customization dialog. Explains to the
          user what action they need to take in the customization dialog to assign a new custom shortcut.
-         The helper is a component that shows the user which keyboard shortcuts they can use.
+         The shortcut customize dialog allows users to add/remove custom shortcuts
          [CHAR LIMIT=NONE] -->
-    <string name="shortcut_helper_customize_mode_sub_title">Press key to assign shortcut</string>
+    <string name="shortcut_customize_mode_add_shortcut_description">Press key to assign shortcut</string>
+    <!-- Sub title at the top of the remove custom shortcut dialog. Explains to the user what action
+         they're about to take when they click remove shortcut. The shortcut customize dialog allows
+         users to add/remove custom shortcuts
+         [CHAR LIMIT=NONE] -->
+    <string name="shortcut_customize_mode_remove_shortcut_description">This will delete your custom shortcut permanently.</string>
     <!-- Placeholder text shown in the search box of the keyboard shortcut helper, when the user
          hasn't typed in anything in the search box yet. The helper is a  component that shows the
          user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] -->
@@ -3807,6 +3824,14 @@
          [CHAR LIMIT=NONE]
           -->
     <string name="shortcut_helper_key_combinations_or_separator">or</string>
+    <!-- Word that combines different possible key combinations of a shortcut. For example the
+         "Go to home screen" shortcut could be triggered using "ctrl" plus "h".
+         This is only used for accessibility content descriptions of the key combinations.
+         [CHAR LIMIT=NONE] -->
+    <string name="shortcut_helper_key_combinations_and_conjunction">plus</string>
+    <!-- Word that represents the forward slash character "/". To be used only in accessibility
+         content descriptions. [CHAR LIMIT=NONE] -->
+    <string name="shortcut_helper_key_combinations_forward_slash">forward slash</string>
     <!-- Content description of the drag handle that allows to swipe to dismiss the shortcut helper.
          The helper is a  component that shows the  user which keyboard shortcuts they can
          use. The helper shows shortcuts in categories, which can be collapsed or expanded.
@@ -3820,6 +3845,10 @@
          confirm and assign key combination to selected shortcut. The helper is a  component that
          shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] -->
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label">Set shortcut</string>
+    <!-- Label on the remove shortcut button in keyboard shortcut helper customize dialog, that allows user to
+         confirm and remove previously added custom shortcut. The helper is a  component that
+         shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] -->
+    <string name="shortcut_helper_customize_dialog_remove_button_label">Remove</string>
     <!-- Label on the cancel button in keyboard shortcut helper customize dialog, that allows user to
          cancel and exit shortcut customization dialog, returning to the main shortcut helper page.
          The helper is a  component that shows the user which keyboard shortcuts they can use.
@@ -3833,13 +3862,17 @@
     <!-- Error message displayed when the user select a key combination that is already in use while
          assigning a new custom key combination to a shortcut in shortcut helper. The helper is a
          component that shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] -->
-    <string name="shortcut_helper_customize_dialog_error_message">Key combination already in use. Try another key.</string>
+    <string name="shortcut_customizer_key_combination_in_use_error_message">Key combination already in use. Try another key.</string>
+    <!-- Generic error message displayed when the user selected key combination cannot be used as
+         custom keyboard shortcut in shortcut helper. The helper is a component that shows the user
+         which keyboard shortcuts they can use and allows users to customize their keyboard
+         shortcuts. [CHAR LIMIT=NONE] -->
+    <string name="shortcut_customizer_generic_error_message">Shortcut cannot be set.</string>
     <!-- Plus sign, used in keyboard shortcut helper to combine keys for shortcut. E.g. Ctrl + A
          The helper is a component that shows the user which keyboard shortcuts they can use.
          [CHAR LIMIT=NONE] -->
     <string name="shortcut_helper_plus_symbol">+</string>
 
-
     <!-- Keyboard touchpad tutorial scheduler-->
     <!-- Notification title for launching keyboard tutorial [CHAR_LIMIT=100] -->
     <string name="launch_keyboard_tutorial_notification_title">Navigate using your keyboard</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index e14008a..9aa7137 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -831,6 +831,11 @@
         <item name="android:textColor">?attr/onSurfaceVariant</item>
     </style>
 
+    <style name="TextAppearance.QSEditTitle" >
+        <item name="android:fontFamily">"gsf-title-medium-emphasized"</item>
+        <item name="android:textColor">?attr/onSurfaceVariant</item>
+    </style>
+
     <style name="QSCustomizeToolbar" parent="@*android:style/Widget.DeviceDefault.Toolbar">
         <item name="android:textColor">?attr/onSurface</item>
         <item name="android:elevation">10dp</item>
@@ -1079,11 +1084,6 @@
         <!-- Setting a placeholder will avoid using the SystemUI icon on the splash screen -->
         <item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_blank</item>
         <item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item>
-
-        <!--
-            TODO(b/309578419): Make the activity handle insets properly and then remove this.
-        -->
-        <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
     </style>
 
     <style name="Widget.SliceView.VolumePanel">
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
index b116e29..dcbacec 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
@@ -16,6 +16,7 @@
 
 package com.android.keyguard;
 
+import static com.android.systemui.Flags.simPinUseSlotId;
 import static com.android.keyguard.logging.CarrierTextManagerLogger.REASON_ACTIVE_DATA_SUB_CHANGED;
 import static com.android.keyguard.logging.CarrierTextManagerLogger.REASON_ON_TELEPHONY_CAPABLE;
 import static com.android.keyguard.logging.CarrierTextManagerLogger.REASON_REFRESH_CARRIER_INFO;
@@ -368,10 +369,12 @@
 
         for (int i = 0; i < numSubs; i++) {
             int subId = subs.get(i).getSubscriptionId();
+            int slotId = subs.get(i).getSimSlotIndex();
             carrierNames[i] = "";
             subsIds[i] = subId;
-            subOrderBySlot[subs.get(i).getSimSlotIndex()] = i;
-            int simState = mKeyguardUpdateMonitor.getSimState(subId);
+            subOrderBySlot[slotId] = i;
+            int simState = simPinUseSlotId() ? mKeyguardUpdateMonitor.getSimStateForSlotId(slotId)
+                    :  mKeyguardUpdateMonitor.getSimState(subId);
             CharSequence carrierName = subs.get(i).getCarrierName();
             CharSequence carrierTextForSimState = getCarrierTextForSimState(simState, carrierName);
             mLogger.logUpdateLoopStart(subId, simState, String.valueOf(carrierName));
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index 8ed675c..6ef7de4 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -16,7 +16,10 @@
 
 package com.android.keyguard;
 
+import static com.android.systemui.Flags.gsfBouncer;
+
 import android.content.Context;
+import android.graphics.Typeface;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
@@ -122,6 +125,9 @@
                 textId = com.android.internal.R.string.lockscreen_emergency_call;
             }
             setText(textId);
+            if (gsfBouncer()) {
+                setTypeface(Typeface.create("gsf-title-medium", Typeface.NORMAL));
+            }
         } else {
             setVisibility(View.GONE);
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 6bcacd0..fcaccd2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -32,6 +32,7 @@
 import static androidx.constraintlayout.widget.ConstraintSet.TOP;
 import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT;
 
+import static com.android.systemui.Flags.gsfBouncer;
 import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
 
 import static java.lang.Integer.max;
@@ -51,6 +52,7 @@
 import android.graphics.BlendMode;
 import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.graphics.Typeface;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
@@ -1335,6 +1337,9 @@
                     true);
             mUserSwitcherViewGroup = mView.findViewById(R.id.keyguard_bouncer_user_switcher);
             mUserSwitcher = mView.findViewById(R.id.user_switcher_header);
+            if (gsfBouncer()) {
+                mUserSwitcher.setTypeface(Typeface.create("gsf-label-medium", Typeface.NORMAL));
+            }
         }
 
         interface UserSwitcherCallback {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 8ca0e80..2c8fff8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -44,6 +44,7 @@
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
 import static com.android.systemui.Flags.simPinBouncerReset;
+import static com.android.systemui.Flags.simPinUseSlotId;
 import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED;
 
 import android.annotation.AnyThread;
@@ -172,7 +173,6 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -318,6 +318,7 @@
 
     private final Object mSimDataLockObject = new Object();
     HashMap<Integer, SimData> mSimDatas = new HashMap<>();
+    HashMap<Integer, SimData> mSimDatasBySlotId = new HashMap<>();
     HashMap<Integer, ServiceState> mServiceStates = new HashMap<>();
 
     private int mPhoneState;
@@ -616,16 +617,17 @@
                 // It is possible for active subscriptions to become invalid (-1), and these will
                 // not be present in the subscriptionInfo list
                 synchronized (mSimDataLockObject) {
-                    Iterator<Map.Entry<Integer, SimData>> iter = mSimDatas.entrySet().iterator();
+                    var iter = simPinUseSlotId() ? mSimDatasBySlotId.entrySet().iterator()
+                            : mSimDatas.entrySet().iterator();
+
                     while (iter.hasNext()) {
-                        Map.Entry<Integer, SimData> simData = iter.next();
-                        if (!activeSubIds.contains(simData.getKey())) {
-                            mSimLogger.logInvalidSubId(simData.getKey());
+                        SimData data = iter.next().getValue();
+                        if (!activeSubIds.contains(data.subId)) {
+                            mSimLogger.logInvalidSubId(data.subId, data.slotId);
                             iter.remove();
 
-                            SimData data = simData.getValue();
                             for (int j = 0; j < mCallbacks.size(); j++) {
-                                KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
+                                var cb = mCallbacks.get(j).get();
                                 if (cb != null) {
                                     cb.onSimStateChanged(data.subId, data.slotId, data.simState);
                                 }
@@ -634,10 +636,15 @@
                     }
 
                     for (int i = 0; i < changedSubscriptions.size(); i++) {
-                        SimData data = mSimDatas.get(
-                                changedSubscriptions.get(i).getSubscriptionId());
+                        SimData data;
+                        if (simPinUseSlotId()) {
+                            data = mSimDatasBySlotId.get(changedSubscriptions.get(i)
+                                .getSimSlotIndex());
+                        } else {
+                            data = mSimDatas.get(changedSubscriptions.get(i).getSubscriptionId());
+                        }
                         for (int j = 0; j < mCallbacks.size(); j++) {
-                            KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
+                            var cb = mCallbacks.get(j).get();
                             if (cb != null) {
                                 cb.onSimStateChanged(data.subId, data.slotId, data.simState);
                             }
@@ -3409,12 +3416,13 @@
      */
     private void invalidateSlot(int slotId) {
         synchronized (mSimDataLockObject) {
-            Iterator<Map.Entry<Integer, SimData>> iter = mSimDatas.entrySet().iterator();
+            var iter = simPinUseSlotId() ? mSimDatasBySlotId.entrySet().iterator()
+                    : mSimDatas.entrySet().iterator();
             while (iter.hasNext()) {
                 SimData data = iter.next().getValue();
                 if (data.slotId == slotId
                         && SubscriptionManager.isValidSubscriptionId(data.subId)) {
-                    mSimLogger.logInvalidSubId(data.subId);
+                    mSimLogger.logInvalidSubId(data.subId, data.slotId);
                     iter.remove();
                 }
             }
@@ -3427,7 +3435,7 @@
     @VisibleForTesting
     void handleSimStateChange(int subId, int slotId, int state) {
         Assert.isMainThread();
-        mSimLogger.logSimState(subId, slotId, state);
+        mSimLogger.logSimState(subId, slotId, TelephonyManager.simStateToString(state));
 
         boolean becameAbsent = ABSENT_SIM_STATE_LIST.contains(state);
         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
@@ -3444,11 +3452,15 @@
 
         // TODO(b/327476182): Preserve SIM_STATE_CARD_IO_ERROR sims in a separate data source.
         synchronized (mSimDataLockObject) {
-            SimData data = mSimDatas.get(subId);
+            SimData data = simPinUseSlotId() ? mSimDatasBySlotId.get(slotId) : mSimDatas.get(subId);
             final boolean changed;
             if (data == null) {
                 data = new SimData(state, slotId, subId);
-                mSimDatas.put(subId, data);
+                if (simPinUseSlotId()) {
+                    mSimDatasBySlotId.put(slotId, data);
+                } else {
+                    mSimDatas.put(subId, data);
+                }
                 changed = true; // no data yet; force update
             } else {
                 changed = (data.simState != state || data.subId != subId || data.slotId != slotId);
@@ -3727,7 +3739,8 @@
         callback.onTelephonyCapable(mTelephonyCapable);
 
         synchronized (mSimDataLockObject) {
-            for (Entry<Integer, SimData> data : mSimDatas.entrySet()) {
+            var simDatas = simPinUseSlotId() ? mSimDatasBySlotId : mSimDatas;
+            for (Entry<Integer, SimData> data : simDatas.entrySet()) {
                 final SimData state = data.getValue();
                 callback.onSimStateChanged(state.subId, state.slotId, state.simState);
             }
@@ -3860,7 +3873,8 @@
      */
     public boolean isSimPinSecure() {
         synchronized (mSimDataLockObject) {
-            for (SimData data : mSimDatas.values()) {
+            var simDatas = simPinUseSlotId() ? mSimDatasBySlotId : mSimDatas;
+            for (SimData data : simDatas.values()) {
                 if (isSimPinSecure(data.simState)) {
                     return true;
                 }
@@ -3870,6 +3884,10 @@
     }
 
     public int getSimState(int subId) {
+        if (simPinUseSlotId()) {
+            throw new UnsupportedOperationException("Method not supported with flag "
+                    + "simPinUseSlotId");
+        }
         synchronized (mSimDataLockObject) {
             if (mSimDatas.containsKey(subId)) {
                 return mSimDatas.get(subId).simState;
@@ -3879,12 +3897,32 @@
         }
     }
 
+    /**
+     * Find the sim state for a slot id, or SIM_STATE_UNKNOWN if not found.
+     */
+    public int getSimStateForSlotId(int slotId) {
+        if (!simPinUseSlotId()) {
+            throw new UnsupportedOperationException("Method not supported without flag "
+                    + "simPinUseSlotId");
+        }
+        synchronized (mSimDataLockObject) {
+            if (mSimDatasBySlotId.containsKey(slotId)) {
+                return mSimDatasBySlotId.get(slotId).simState;
+            } else {
+                return TelephonyManager.SIM_STATE_UNKNOWN;
+            }
+        }
+    }
+
     private int getSlotId(int subId) {
         synchronized (mSimDataLockObject) {
-            if (!mSimDatas.containsKey(subId)) {
-                refreshSimState(subId, SubscriptionManager.getSlotIndex(subId));
+            var simDatas = simPinUseSlotId() ? mSimDatasBySlotId : mSimDatas;
+            int slotId = SubscriptionManager.getSlotIndex(subId);
+            int index = simPinUseSlotId() ? slotId : subId;
+            if (!simDatas.containsKey(index)) {
+                refreshSimState(subId, slotId);
             }
-            SimData simData = mSimDatas.get(subId);
+            SimData simData = simDatas.get(index);
             return simData != null ? simData.slotId : SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         }
     }
@@ -3928,8 +3966,7 @@
     private boolean refreshSimState(int subId, int slotId) {
         int state = mTelephonyManager.getSimState(slotId);
         synchronized (mSimDataLockObject) {
-            SimData data = mSimDatas.get(subId);
-
+            SimData data = simPinUseSlotId() ? mSimDatasBySlotId.get(slotId) : mSimDatas.get(subId);
             if (!SubscriptionManager.isValidSubscriptionId(subId)) {
                 invalidateSlot(slotId);
             }
@@ -3937,7 +3974,11 @@
             final boolean changed;
             if (data == null) {
                 data = new SimData(state, slotId, subId);
-                mSimDatas.put(subId, data);
+                if (simPinUseSlotId()) {
+                    mSimDatasBySlotId.put(slotId, data);
+                } else {
+                    mSimDatas.put(subId, data);
+                }
                 changed = true; // no data yet; force update
             } else {
                 changed = data.simState != state;
@@ -4033,10 +4074,17 @@
         for (int i = 0; i < list.size(); i++) {
             final SubscriptionInfo info = list.get(i);
             final int id = info.getSubscriptionId();
-            int slotId = getSlotId(id);
-            if (state == getSimState(id) && bestSlotId > slotId) {
-                resultId = id;
-                bestSlotId = slotId;
+            final int slotId = info.getSimSlotIndex();
+            if (simPinUseSlotId()) {
+                if (state == getSimStateForSlotId(slotId) && bestSlotId > slotId) {
+                    resultId = id;
+                    bestSlotId = slotId;
+                }
+            } else {
+                if (state == getSimState(id) && bestSlotId > slotId) {
+                    resultId = id;
+                    bestSlotId = slotId;
+                }
             }
         }
         return resultId;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
index 9513c8e..5a9cbce 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
@@ -174,9 +174,20 @@
 
     /**
      * Stop showing the alternate bouncer, if showing.
+     *
+     * <p>Should be like calling {@link #hideAlternateBouncer(boolean, boolean)} with a {@code true}
+     * {@code clearDismissAction} parameter.
      */
     void hideAlternateBouncer(boolean updateScrim);
 
+    /**
+     * Stop showing the alternate bouncer, if showing.
+     *
+     * @param updateScrim Whether to update the scrim
+     * @param clearDismissAction Whether the pending dismiss action should be cleared
+     */
+    void hideAlternateBouncer(boolean updateScrim, boolean clearDismissAction);
+
     // TODO: Deprecate registerStatusBar in KeyguardViewController interface. It is currently
     //  only used for testing purposes in StatusBarKeyguardViewManager, and it prevents us from
     //  achieving complete abstraction away from where the Keyguard View is mounted.
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 7fe4ec8..ebde8a3 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -15,11 +15,13 @@
  */
 package com.android.keyguard;
 
+import static com.android.systemui.Flags.gsfBouncer;
 import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_KEY;
 
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
+import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.os.PowerManager;
@@ -158,6 +160,9 @@
         int klondikeColor = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary)
                 .getDefaultColor();
         mDigitText.setTextColor(textColor);
+        if (gsfBouncer()) {
+            mDigitText.setTypeface(Typeface.create("gsf-label-large-emphasized", Typeface.NORMAL));
+        }
         mKlondikeText.setTextColor(klondikeColor);
 
         if (mAnimator != null) mAnimator.reloadColors(getContext());
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/SimLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/SimLogger.kt
index a81698b..fb26c6a 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/SimLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/SimLogger.kt
@@ -47,12 +47,15 @@
 
     fun log(@CompileTimeConstant msg: String, level: LogLevel) = logBuffer.log(TAG, level, msg)
 
-    fun logInvalidSubId(subId: Int) {
+    fun logInvalidSubId(subId: Int, slotId: Int) {
         logBuffer.log(
             TAG,
             INFO,
-            { int1 = subId },
-            { "Previously active sub id $int1 is now invalid, will remove" },
+            {
+                int1 = subId
+                int2 = slotId
+            },
+            { "Previously active subId: $int1, slotId: $int2 is now invalid, will remove" },
         )
     }
 
@@ -94,16 +97,16 @@
         )
     }
 
-    fun logSimState(subId: Int, slotId: Int, state: Int) {
+    fun logSimState(subId: Int, slotId: Int, state: String) {
         logBuffer.log(
             TAG,
             DEBUG,
             {
                 int1 = subId
                 int2 = slotId
-                long1 = state.toLong()
+                str1 = state
             },
-            { "handleSimStateChange(subId=$int1, slotId=$int2, state=$long1)" },
+            { "handleSimStateChange(subId=$int1, slotId=$int2, state=$str1)" },
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 7d5cf23..08d3e17 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -283,7 +283,7 @@
                 com.android.internal.R.integer.config_shortAnimTime));
         updateDimensions();
 
-        final Size windowFrameSize = restoreMagnificationWindowFrameSizeIfPossible();
+        final Size windowFrameSize = restoreMagnificationWindowFrameIndexAndSizeIfPossible();
         setMagnificationFrame(windowFrameSize.getWidth(), windowFrameSize.getHeight(),
                 mWindowBounds.width() / 2, mWindowBounds.height() / 2);
         computeBounceAnimationScale();
@@ -541,7 +541,7 @@
             return false;
         }
         mWindowBounds.set(currentWindowBounds);
-        final Size windowFrameSize = restoreMagnificationWindowFrameSizeIfPossible();
+        final Size windowFrameSize = restoreMagnificationWindowFrameIndexAndSizeIfPossible();
         final float newCenterX = (getCenterX()) * mWindowBounds.width() / oldWindowBounds.width();
         final float newCenterY = (getCenterY()) * mWindowBounds.height() / oldWindowBounds.height();
 
@@ -787,18 +787,6 @@
         mMagnificationFrame.set(initX, initY, initX + width, initY + height);
     }
 
-    private Size restoreMagnificationWindowFrameSizeIfPossible() {
-        if (Flags.saveAndRestoreMagnificationSettingsButtons()) {
-            return restoreMagnificationWindowFrameIndexAndSizeIfPossible();
-        }
-
-        if (!mWindowMagnificationFrameSizePrefs.isPreferenceSavedForCurrentDensity()) {
-            return getDefaultMagnificationWindowFrameSize();
-        }
-
-        return mWindowMagnificationFrameSizePrefs.getSizeForCurrentDensity();
-    }
-
     private Size restoreMagnificationWindowFrameIndexAndSizeIfPossible() {
         if (!mWindowMagnificationFrameSizePrefs.isPreferenceSavedForCurrentDensity()) {
             notifyWindowSizeRestored(MagnificationSize.DEFAULT);
@@ -845,9 +833,7 @@
         }
         // Set the surface of the SurfaceView to black to avoid users seeing the contents below the
         // magnifier when the mirrored surface has an alpha less than 1.
-        if (Flags.addBlackBackgroundForWindowMagnifier()) {
-            mTransaction.setColor(mMirrorSurfaceView.getSurfaceControl(), COLOR_BLACK_ARRAY);
-        }
+        mTransaction.setColor(mMirrorSurfaceView.getSurfaceControl(), COLOR_BLACK_ARRAY);
         mTransaction.show(mMirrorSurface)
                 .reparent(mMirrorSurface, mMirrorSurfaceView.getSurfaceControl());
         modifyWindowMagnification(false);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefs.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefs.java
index ee36c6e..558c87c 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefs.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefs.java
@@ -22,8 +22,6 @@
 import android.content.SharedPreferences;
 import android.util.Size;
 
-import com.android.systemui.Flags;
-
 /**
  * Class to handle SharedPreference for window magnification size.
  */
@@ -52,14 +50,10 @@
      * Saves the window frame size for current screen density.
      */
     public void saveIndexAndSizeForCurrentDensity(int index, Size size) {
-        if (Flags.saveAndRestoreMagnificationSettingsButtons()) {
-            mWindowMagnificationSizePreferences.edit()
-                    .putString(getKey(),
-                            WindowMagnificationFrameSpec.serialize(index, size)).apply();
-        } else {
-            mWindowMagnificationSizePreferences.edit()
-                    .putString(getKey(), size.toString()).apply();
-        }
+        mWindowMagnificationSizePreferences
+                .edit()
+                .putString(getKey(), WindowMagnificationFrameSpec.serialize(index, size))
+                .apply();
     }
 
     /**
@@ -91,13 +85,9 @@
      * Gets the size preference for current screen density.
      */
     public Size getSizeForCurrentDensity() {
-        if (Flags.saveAndRestoreMagnificationSettingsButtons()) {
-            return WindowMagnificationFrameSpec
-                    .deserialize(mWindowMagnificationSizePreferences.getString(getKey(), null))
-                    .getSize();
-        } else {
-            return Size.parseSize(mWindowMagnificationSizePreferences.getString(getKey(), null));
-        }
+        return WindowMagnificationFrameSpec.deserialize(
+                        mWindowMagnificationSizePreferences.getString(getKey(), null))
+                .getSize();
     }
 
 }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
index 2f0ca6e..9d9f569 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
@@ -59,7 +59,6 @@
 import com.android.app.viewcapture.ViewCaptureAwareWindowManager;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
-import com.android.systemui.Flags;
 import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView;
 import com.android.systemui.res.R;
 import com.android.systemui.util.settings.SecureSettings;
@@ -460,12 +459,8 @@
                 mAllowDiagonalScrollingView.setVisibility(View.VISIBLE);
                 mFullScreenButton.setVisibility(View.GONE);
                 if (selectedButtonIndex == MagnificationSize.FULLSCREEN) {
-                    if (Flags.saveAndRestoreMagnificationSettingsButtons()) {
-                        selectedButtonIndex =
-                                windowMagnificationFrameSizePrefs.getIndexForCurrentDensity();
-                    } else {
-                        selectedButtonIndex = MagnificationSize.CUSTOM;
-                    }
+                    selectedButtonIndex =
+                            windowMagnificationFrameSizePrefs.getIndexForCurrentDensity();
                 }
                 break;
 
@@ -482,10 +477,8 @@
                 } else { // mode = ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
                     mEditButton.setVisibility(View.VISIBLE);
                     mAllowDiagonalScrollingView.setVisibility(View.VISIBLE);
-                    if (Flags.saveAndRestoreMagnificationSettingsButtons()) {
-                        selectedButtonIndex =
-                                windowMagnificationFrameSizePrefs.getIndexForCurrentDensity();
-                    }
+                    selectedButtonIndex =
+                            windowMagnificationFrameSizePrefs.getIndexForCurrentDensity();
                 }
                 break;
 
@@ -581,13 +574,15 @@
                 || (configDiff & ActivityInfo.CONFIG_ASSETS_PATHS) != 0
                 || (configDiff & ActivityInfo.CONFIG_FONT_SCALE) != 0
                 || (configDiff & ActivityInfo.CONFIG_LOCALE) != 0
-                || (configDiff & ActivityInfo.CONFIG_DENSITY) != 0) {
+                || (configDiff & ActivityInfo.CONFIG_DENSITY) != 0
+                || (configDiff & ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT) != 0) {
             // We listen to following config changes to trigger layout inflation:
             // CONFIG_UI_MODE: theme change
             // CONFIG_ASSETS_PATHS: wallpaper change
             // CONFIG_FONT_SCALE: font size change
             // CONFIG_LOCALE: language change
             // CONFIG_DENSITY: display size change
+            // CONFIG_FONT_WEIGHT_ADJUSTMENT: bold text setting change
             mParams.width = getPanelWidth(mContext);
             mParams.accessibilityTitle = getAccessibilityWindowTitle(mContext);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt b/packages/SystemUI/src/com/android/systemui/activity/ActivityManagerModule.kt
similarity index 66%
copy from packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
copy to packages/SystemUI/src/com/android/systemui/activity/ActivityManagerModule.kt
index 83551e9..db315e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/activity/ActivityManagerModule.kt
@@ -14,15 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.phone
+package com.android.systemui.activity
 
+import com.android.systemui.activity.data.repository.ActivityManagerRepository
+import com.android.systemui.activity.data.repository.ActivityManagerRepositoryImpl
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.policy.BaseHeadsUpManager
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import dagger.Binds
 import dagger.Module
 
 @Module
-interface HeadsUpModule {
-    @Binds @SysUISingleton fun bindsHeadsUpManager(hum: BaseHeadsUpManager): HeadsUpManager
+interface ActivityManagerModule {
+    @Binds
+    @SysUISingleton
+    fun activityManagerRepository(impl: ActivityManagerRepositoryImpl): ActivityManagerRepository
 }
diff --git a/packages/SystemUI/src/com/android/systemui/activity/data/repository/ActivityManagerRepository.kt b/packages/SystemUI/src/com/android/systemui/activity/data/repository/ActivityManagerRepository.kt
new file mode 100644
index 0000000..94614b7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/activity/data/repository/ActivityManagerRepository.kt
@@ -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 com.android.systemui.activity.data.repository
+
+import android.app.ActivityManager
+import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.log.core.Logger
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.onStart
+
+/** Repository for interfacing with [ActivityManager]. */
+interface ActivityManagerRepository {
+    /**
+     * Given a UID, creates a flow that emits true when the process with the given UID is visible to
+     * the user and false otherwise.
+     *
+     * @param identifyingLogTag a tag identifying who created this flow, used for logging.
+     */
+    fun createIsAppVisibleFlow(
+        creationUid: Int,
+        logger: Logger,
+        identifyingLogTag: String,
+    ): Flow<Boolean>
+}
+
+@SysUISingleton
+class ActivityManagerRepositoryImpl
+@Inject
+constructor(
+    @Background private val backgroundContext: CoroutineContext,
+    private val activityManager: ActivityManager,
+) : ActivityManagerRepository {
+    override fun createIsAppVisibleFlow(
+        creationUid: Int,
+        logger: Logger,
+        identifyingLogTag: String,
+    ): Flow<Boolean> {
+        return conflatedCallbackFlow {
+                val listener =
+                    object : ActivityManager.OnUidImportanceListener {
+                        override fun onUidImportance(uid: Int, importance: Int) {
+                            if (uid != creationUid) {
+                                return
+                            }
+                            val isAppVisible = isAppVisibleToUser(importance)
+                            logger.d({
+                                "$str1: #onUidImportance. importance=$int1, isAppVisible=$bool1"
+                            }) {
+                                str1 = identifyingLogTag
+                                int1 = importance
+                                bool1 = isAppVisible
+                            }
+                            trySend(isAppVisible)
+                        }
+                    }
+                try {
+                    // TODO(b/286258140): Replace this with the #addOnUidImportanceListener
+                    //  overload that filters to certain UIDs.
+                    activityManager.addOnUidImportanceListener(listener, IMPORTANCE_CUTPOINT)
+                } catch (e: SecurityException) {
+                    logger.e({ "$str1: Security exception on #addOnUidImportanceListener" }, e) {
+                        str1 = identifyingLogTag
+                    }
+                }
+
+                awaitClose { activityManager.removeOnUidImportanceListener(listener) }
+            }
+            .distinctUntilChanged()
+            .onStart {
+                try {
+                    val isVisibleOnStart =
+                        isAppVisibleToUser(activityManager.getUidImportance(creationUid))
+                    logger.d({ "$str1: Starting UID observation. isAppVisible=$bool1" }) {
+                        str1 = identifyingLogTag
+                        bool1 = isVisibleOnStart
+                    }
+                    emit(isVisibleOnStart)
+                } catch (e: SecurityException) {
+                    logger.e({ "$str1: Security exception on #getUidImportance" }, e) {
+                        str1 = identifyingLogTag
+                    }
+                    emit(false)
+                }
+            }
+            .flowOn(backgroundContext)
+    }
+
+    /** Returns true if the given [importance] represents an app that's visible to the user. */
+    private fun isAppVisibleToUser(importance: Int): Boolean {
+        return importance <= IMPORTANCE_CUTPOINT
+    }
+
+    companion object {
+        private const val IMPORTANCE_CUTPOINT = IMPORTANCE_FOREGROUND
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index e634726..1176cb0 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -19,6 +19,7 @@
 
 import static com.android.settingslib.flags.Flags.newStatusBarIcons;
 import static com.android.systemui.DejankUtils.whitelistIpcs;
+import static com.android.systemui.Flags.gsfQuickSettings;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -33,6 +34,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Rect;
+import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -384,6 +386,9 @@
         }
         float fontHeight = mBatteryPercentView.getPaint().getFontMetricsInt(null);
         mBatteryPercentView.setLineHeight(TypedValue.COMPLEX_UNIT_PX, fontHeight);
+        if (gsfQuickSettings()) {
+            mBatteryPercentView.setTypeface(Typeface.create("gsf-label-large", Typeface.NORMAL));
+        }
         if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
         addView(mBatteryPercentView, new LayoutParams(
                 LayoutParams.WRAP_CONTENT,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index b491c94..f6b6655 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -64,6 +64,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.biometrics.AuthController.ScaleFactorProvider;
 import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor;
+import com.android.systemui.biometrics.plugins.AuthContextPlugins;
 import com.android.systemui.biometrics.shared.model.BiometricModalities;
 import com.android.systemui.biometrics.shared.model.PromptKind;
 import com.android.systemui.biometrics.ui.CredentialView;
@@ -132,6 +133,7 @@
     private final int mEffectiveUserId;
     private final IBinder mWindowToken = new Binder();
     private final ViewCaptureAwareWindowManager mWindowManager;
+    @Nullable private final AuthContextPlugins mAuthContextPlugins;
     private final Interpolator mLinearOutSlowIn;
     private final LockPatternUtils mLockPatternUtils;
     private final WakefulnessLifecycle mWakefulnessLifecycle;
@@ -289,6 +291,7 @@
             @Nullable List<FaceSensorPropertiesInternal> faceProps,
             @NonNull WakefulnessLifecycle wakefulnessLifecycle,
             @NonNull UserManager userManager,
+            @Nullable AuthContextPlugins authContextPlugins,
             @NonNull LockPatternUtils lockPatternUtils,
             @NonNull InteractionJankMonitor jankMonitor,
             @NonNull Provider<PromptSelectorInteractor> promptSelectorInteractorProvider,
@@ -306,6 +309,7 @@
         WindowManager wm = getContext().getSystemService(WindowManager.class);
         mWindowManager = new ViewCaptureAwareWindowManager(wm, lazyViewCapture,
                 enableViewCaptureTracing());
+        mAuthContextPlugins = authContextPlugins;
         mWakefulnessLifecycle = wakefulnessLifecycle;
         mApplicationCoroutineScope = applicationCoroutineScope;
 
@@ -446,7 +450,7 @@
         final CredentialViewModel vm = mCredentialViewModelProvider.get();
         vm.setAnimateContents(animateContents);
         ((CredentialView) mCredentialView).init(vm, this, mPanelController, animatePanel,
-                mBiometricCallback);
+                mBiometricCallback, mAuthContextPlugins);
 
         mLayout.addView(mCredentialView);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index a5bd559..4faf6ff 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -21,6 +21,7 @@
 import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR;
 import static android.view.Display.INVALID_DISPLAY;
 
+import static com.android.systemui.Flags.contAuthPlugin;
 import static com.android.systemui.util.ConvenienceExtensionsKt.toKotlinLazy;
 
 import android.annotation.NonNull;
@@ -74,6 +75,7 @@
 import com.android.systemui.CoreStartable;
 import com.android.systemui.biometrics.domain.interactor.LogContextInteractor;
 import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor;
+import com.android.systemui.biometrics.plugins.AuthContextPlugins;
 import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
 import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
 import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel;
@@ -108,6 +110,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 
 import javax.inject.Inject;
@@ -139,6 +142,7 @@
     private final ActivityTaskManager mActivityTaskManager;
     @Nullable private final FingerprintManager mFingerprintManager;
     @Nullable private final FaceManager mFaceManager;
+    @Nullable private final AuthContextPlugins mContextPlugins;
     private final Provider<UdfpsController> mUdfpsControllerFactory;
     private final CoroutineScope mApplicationCoroutineScope;
     private Job mBiometricContextListenerJob = null;
@@ -717,6 +721,7 @@
             @NonNull WindowManager windowManager,
             @Nullable FingerprintManager fingerprintManager,
             @Nullable FaceManager faceManager,
+            Optional<AuthContextPlugins> contextPlugins,
             Provider<UdfpsController> udfpsControllerFactory,
             @NonNull DisplayManager displayManager,
             @NonNull WakefulnessLifecycle wakefulnessLifecycle,
@@ -744,6 +749,7 @@
         mActivityTaskManager = activityTaskManager;
         mFingerprintManager = fingerprintManager;
         mFaceManager = faceManager;
+        mContextPlugins = contAuthPlugin() ? contextPlugins.orElse(null) : null;
         mUdfpsControllerFactory = udfpsControllerFactory;
         mUdfpsLogger = udfpsLogger;
         mDisplayManager = displayManager;
@@ -858,6 +864,10 @@
         mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
         mOrientationListener.enable();
         updateSensorLocations();
+
+        if (mContextPlugins != null) {
+            mContextPlugins.activate();
+        }
     }
 
     @Override
@@ -1350,7 +1360,7 @@
         config.mSensorIds = sensorIds;
         config.mScaleProvider = this::getScaleFactor;
         return new AuthContainerView(config, mApplicationCoroutineScope, mFpProps, mFaceProps,
-                wakefulnessLifecycle, userManager, lockPatternUtils,
+                wakefulnessLifecycle, userManager, mContextPlugins, lockPatternUtils,
                 mInteractionJankMonitor, mPromptSelectorInteractor, viewModel,
                 mCredentialViewModelProvider, bgExecutor, mVibratorHelper,
                 mLazyViewCapture, mMSDLPlayer);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 2863e29..a9133e4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -814,6 +814,11 @@
     private void showUdfpsOverlay(@NonNull UdfpsControllerOverlay overlay) {
         mExecution.assertIsMainThread();
 
+        if (mOverlay != null) {
+            Log.d(TAG, "showUdfpsOverlay | the overlay is already showing");
+            return;
+        }
+
         mOverlay = overlay;
         final int requestReason = overlay.getRequestReason();
         if (requestReason == REASON_AUTH_KEYGUARD
@@ -823,7 +828,7 @@
             return;
         }
         if (overlay.show(this, mOverlayParams)) {
-            Log.v(TAG, "showUdfpsOverlay | adding window reason=" + requestReason);
+            Log.d(TAG, "showUdfpsOverlay | adding window reason=" + requestReason);
             mOnFingerDown = false;
             mAttemptedToDismissKeyguard = false;
             mOrientationListener.enable();
@@ -832,7 +837,7 @@
                         overlay.getRequestId(), mSensorProps.sensorId);
             }
         } else {
-            Log.v(TAG, "showUdfpsOverlay | the overlay is already showing");
+            Log.d(TAG, "showUdfpsOverlay | the overlay is already showing");
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index 2593ceb..51eb139 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -41,6 +41,7 @@
 import android.view.accessibility.AccessibilityManager
 import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener
 import androidx.annotation.VisibleForTesting
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.app.viewcapture.ViewCaptureAwareWindowManager
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.animation.ActivityTransitionAnimator
@@ -73,7 +74,6 @@
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.map
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 private const val TAG = "UdfpsControllerOverlay"
 
@@ -245,7 +245,7 @@
             return true
         }
 
-        Log.v(TAG, "showUdfpsOverlay | the overlay is already showing")
+        Log.d(TAG, "showUdfpsOverlay | the overlay is already showing")
         return false
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
index e2a8a69..60ce177 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepositoryImpl
 import com.android.systemui.biometrics.data.repository.PromptRepository
 import com.android.systemui.biometrics.data.repository.PromptRepositoryImpl
+import com.android.systemui.biometrics.plugins.AuthContextPlugins
 import com.android.systemui.biometrics.udfps.BoundingBoxOverlapDetector
 import com.android.systemui.biometrics.udfps.EllipseOverlapDetector
 import com.android.systemui.biometrics.udfps.OverlapDetector
@@ -58,7 +59,7 @@
 /** Dagger module for all things biometric. */
 @Module
 interface BiometricsModule {
-    /** Starts AuthController.  */
+    /** Starts AuthController. */
     @Binds
     @IntoMap
     @ClassKey(AuthController::class)
@@ -103,8 +104,9 @@
     @SysUISingleton
     fun displayStateRepository(impl: DisplayStateRepositoryImpl): DisplayStateRepository
 
-    @BindsOptionalOf
-    fun deviceEntryUnlockTrackerViewBinder(): DeviceEntryUnlockTrackerViewBinder
+    @BindsOptionalOf fun authContextPlugins(): AuthContextPlugins
+
+    @BindsOptionalOf fun deviceEntryUnlockTrackerViewBinder(): DeviceEntryUnlockTrackerViewBinder
 
     companion object {
         /** Background [Executor] for HAL related operations. */
@@ -117,8 +119,7 @@
 
         @Provides fun providesUdfpsUtils(): UdfpsUtils = UdfpsUtils()
 
-        @Provides
-        fun provideIconProvider(context: Context): IconProvider = IconProvider(context)
+        @Provides fun provideIconProvider(context: Context): IconProvider = IconProvider(context)
 
         @Provides
         @SysUISingleton
@@ -136,7 +137,7 @@
                     EllipseOverlapDetectorParams(
                         minOverlap = values[3],
                         targetSize = values[2],
-                        stepSize = values[4].toInt()
+                        stepSize = values[4].toInt(),
                     )
                 )
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/plugins/AuthContextPlugins.kt b/packages/SystemUI/src/com/android/systemui/biometrics/plugins/AuthContextPlugins.kt
new file mode 100644
index 0000000..ca38e98
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/plugins/AuthContextPlugins.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.biometrics.plugins
+
+import com.android.systemui.plugins.AuthContextPlugin
+import com.android.systemui.plugins.PluginManager
+
+/** Wrapper interface for registering & forwarding events to all available [AuthContextPlugin]s. */
+interface AuthContextPlugins {
+    /** Finds and actives all plugins via SysUI's [PluginManager] (should be called at startup). */
+    fun activate()
+
+    /**
+     * Interact with all registered plugins.
+     *
+     * The provided [block] will be repeated for each available plugin.
+     */
+    suspend fun use(block: (AuthContextPlugin) -> Unit)
+
+    /**
+     * Like [use] but when no existing coroutine context is available.
+     *
+     * The [block] will be run on SysUI's general background context and can, optionally, be
+     * confined to [runOnMain] (defaults to a background thread).
+     */
+    fun useInBackground(runOnMain: Boolean = false, block: (AuthContextPlugin) -> Unit)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt
index b28733f..dad140f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt
@@ -11,6 +11,7 @@
 import android.widget.LinearLayout
 import android.widget.TextView
 import com.android.systemui.biometrics.AuthPanelController
+import com.android.systemui.biometrics.plugins.AuthContextPlugins
 import com.android.systemui.biometrics.ui.binder.CredentialViewBinder
 import com.android.systemui.biometrics.ui.binder.Spaghetti
 import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
@@ -33,6 +34,7 @@
         panelViewController: AuthPanelController,
         animatePanel: Boolean,
         legacyCallback: Spaghetti.Callback,
+        plugins: AuthContextPlugins?,
     ) {
         CredentialViewBinder.bind(
             this,
@@ -40,7 +42,8 @@
             viewModel,
             panelViewController,
             animatePanel,
-            legacyCallback
+            legacyCallback,
+            plugins,
         )
     }
 
@@ -78,7 +81,7 @@
             0,
             statusBarInsets.top,
             0,
-            if (keyboardInsets.bottom == 0) navigationInsets.bottom else keyboardInsets.bottom
+            if (keyboardInsets.bottom == 0) navigationInsets.bottom else keyboardInsets.bottom,
         )
         return WindowInsets.CONSUMED
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPatternView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPatternView.kt
index d9d286f..e80a79b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPatternView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPatternView.kt
@@ -8,6 +8,7 @@
 import android.view.WindowInsets.Type
 import android.widget.LinearLayout
 import com.android.systemui.biometrics.AuthPanelController
+import com.android.systemui.biometrics.plugins.AuthContextPlugins
 import com.android.systemui.biometrics.ui.binder.CredentialViewBinder
 import com.android.systemui.biometrics.ui.binder.Spaghetti
 import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
@@ -23,6 +24,7 @@
         panelViewController: AuthPanelController,
         animatePanel: Boolean,
         legacyCallback: Spaghetti.Callback,
+        plugins: AuthContextPlugins?,
     ) {
         CredentialViewBinder.bind(
             this,
@@ -30,7 +32,8 @@
             viewModel,
             panelViewController,
             animatePanel,
-            legacyCallback
+            legacyCallback,
+            plugins,
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialView.kt
index e2f9895..f3e4917 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialView.kt
@@ -1,6 +1,7 @@
 package com.android.systemui.biometrics.ui
 
 import com.android.systemui.biometrics.AuthPanelController
+import com.android.systemui.biometrics.plugins.AuthContextPlugins
 import com.android.systemui.biometrics.ui.binder.Spaghetti
 import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
 
@@ -29,5 +30,6 @@
         panelViewController: AuthPanelController,
         animatePanel: Boolean,
         legacyCallback: Spaghetti.Callback,
+        plugins: AuthContextPlugins?,
     )
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
index 39543e7..10b1211 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
@@ -9,18 +9,21 @@
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.app.animation.Interpolators
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.biometrics.AuthPanelController
+import com.android.systemui.biometrics.plugins.AuthContextPlugins
 import com.android.systemui.biometrics.ui.CredentialPasswordView
 import com.android.systemui.biometrics.ui.CredentialPatternView
 import com.android.systemui.biometrics.ui.CredentialView
 import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.plugins.AuthContextPlugin
 import com.android.systemui.res.R
 import kotlinx.coroutines.Job
+import kotlinx.coroutines.awaitCancellation
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.onEach
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 private const val ANIMATE_CREDENTIAL_INITIAL_DURATION_MS = 150
 
@@ -42,6 +45,7 @@
         panelViewController: AuthPanelController,
         animatePanel: Boolean,
         legacyCallback: Spaghetti.Callback,
+        plugins: AuthContextPlugins?,
         maxErrorDuration: Long = 3_000L,
         requestFocusForInput: Boolean = true,
     ) {
@@ -72,6 +76,10 @@
             }
 
             repeatOnLifecycle(Lifecycle.State.STARTED) {
+                if (plugins != null) {
+                    launch { plugins.notifyShowingBPCredential(view) }
+                }
+
                 // show prompt metadata
                 launch {
                     viewModel.header.collect { header ->
@@ -136,6 +144,12 @@
                             host.onCredentialAttemptsRemaining(info.remaining!!, info.message)
                         }
                 }
+
+                try {
+                    awaitCancellation()
+                } catch (_: Throwable) {
+                    plugins?.notifyHidingBPCredential()
+                }
             }
         }
 
@@ -172,3 +186,15 @@
         text = if (gone) "" else value
     }
     get() = text?.toString()
+
+private suspend fun AuthContextPlugins.notifyShowingBPCredential(view: View) = use { plugin ->
+    plugin.onShowingSensitiveSurface(
+        AuthContextPlugin.SensitiveSurface.BiometricPrompt(view = view, isCredential = true)
+    )
+}
+
+private fun AuthContextPlugins.notifyHidingBPCredential() = useInBackground { plugin ->
+    plugin.onHidingSensitiveSurface(
+        AuthContextPlugin.SensitiveSurface.BiometricPrompt(isCredential = true)
+    )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorImpl.kt
index 13c7209..4dc2a13 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorImpl.kt
@@ -27,7 +27,6 @@
 import com.android.settingslib.bluetooth.LeAudioProfile
 import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
 import com.android.settingslib.bluetooth.LocalBluetoothManager
-import com.android.settingslib.flags.Flags.audioSharingQsDialogImprovement
 import com.android.systemui.animation.DialogTransitionAnimator
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
@@ -69,7 +68,7 @@
                 }
                 deviceItem.type ==
                     DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE -> {
-                    if (audioSharingQsDialogImprovement()) {
+                    if (audioSharingInteractor.qsDialogImprovementAvailable()) {
                         withContext(mainDispatcher) {
                             delegateFactory
                                 .create(deviceItem.cachedBluetoothDevice)
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt
index 65f1105..c4f26cd 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt
@@ -16,10 +16,13 @@
 
 package com.android.systemui.bluetooth.qsdialog
 
+import android.content.Context
+import androidx.annotation.WorkerThread
 import com.android.settingslib.bluetooth.BluetoothUtils
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
 import com.android.settingslib.bluetooth.LocalBluetoothManager
-import com.android.settingslib.bluetooth.onPlaybackStarted
+import com.android.settingslib.bluetooth.onBroadcastMetadataChanged
+import com.android.settingslib.flags.Flags.audioSharingQsDialogImprovement
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import javax.inject.Inject
@@ -52,6 +55,8 @@
     suspend fun startAudioSharing()
 
     suspend fun audioSharingAvailable(): Boolean
+
+    suspend fun qsDialogImprovementAvailable(): Boolean
 }
 
 @SysUISingleton
@@ -59,11 +64,14 @@
 class AudioSharingInteractorImpl
 @Inject
 constructor(
+    private val context: Context,
     private val localBluetoothManager: LocalBluetoothManager?,
     private val audioSharingRepository: AudioSharingRepository,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
 ) : AudioSharingInteractor {
 
+    private var previewEnabled: Boolean? = null
+
     override val isAudioSharingOn: Flow<Boolean> =
         flow { emit(audioSharingAvailable()) }
             .flatMapLatest { isEnabled ->
@@ -93,10 +101,10 @@
                     isAudioSharingOn
                         .mapNotNull { audioSharingOn ->
                             if (audioSharingOn) {
-                                // onPlaybackStarted could emit multiple times during one
-                                // audio sharing session, we only perform add source on the
-                                // first time
-                                profile.onPlaybackStarted.firstOrNull()
+                                // onBroadcastMetadataChanged could emit multiple times during one
+                                // audio sharing session, we only perform add source on the first
+                                // time
+                                profile.onBroadcastMetadataChanged.firstOrNull()
                             } else {
                                 null
                             }
@@ -141,6 +149,20 @@
     override suspend fun audioSharingAvailable(): Boolean {
         return audioSharingRepository.audioSharingAvailable()
     }
+
+    override suspend fun qsDialogImprovementAvailable(): Boolean {
+        return withContext(backgroundDispatcher) {
+            audioSharingQsDialogImprovement() || isAudioSharingPreviewEnabled()
+        }
+    }
+
+    @WorkerThread
+    private fun isAudioSharingPreviewEnabled(): Boolean {
+        if (previewEnabled == null) {
+            previewEnabled = BluetoothUtils.isAudioSharingPreviewEnabled(context.contentResolver)
+        }
+        return previewEnabled ?: false
+    }
 }
 
 @SysUISingleton
@@ -160,4 +182,6 @@
     override suspend fun startAudioSharing() {}
 
     override suspend fun audioSharingAvailable(): Boolean = false
+
+    override suspend fun qsDialogImprovementAvailable(): Boolean = false
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt
index b255a4f..497d8cf 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt
@@ -26,10 +26,10 @@
 import androidx.annotation.DimenRes
 import androidx.annotation.StringRes
 import androidx.annotation.VisibleForTesting
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.logging.UiEventLogger
 import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
-import com.android.settingslib.flags.Flags.audioSharingQsDialogImprovement
 import com.android.systemui.Prefs
 import com.android.systemui.animation.DialogCuj
 import com.android.systemui.animation.DialogTransitionAnimator
@@ -56,7 +56,6 @@
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.onEach
-import com.android.app.tracing.coroutines.launchTraced as launch
 import kotlinx.coroutines.withContext
 
 /** ViewModel for Bluetooth Dialog after clicking on the Bluetooth QS tile. */
@@ -145,7 +144,7 @@
                         bluetoothDeviceMetadataInteractor.metadataUpdate,
                         if (
                             audioSharingInteractor.audioSharingAvailable() &&
-                                audioSharingQsDialogImprovement()
+                                audioSharingInteractor.qsDialogImprovementAvailable()
                         ) {
                             audioSharingInteractor.audioSourceStateUpdate
                         } else {
@@ -165,7 +164,7 @@
                     .launchIn(this)
 
                 if (audioSharingInteractor.audioSharingAvailable()) {
-                    if (audioSharingQsDialogImprovement()) {
+                    if (audioSharingInteractor.qsDialogImprovementAvailable()) {
                         launch { audioSharingInteractor.handleAudioSourceWhenReady() }
                     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/dagger/AudioSharingModule.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/dagger/AudioSharingModule.kt
index 8b5fde3..afe9a1e 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/dagger/AudioSharingModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/dagger/AudioSharingModule.kt
@@ -55,7 +55,10 @@
             settingsLibAudioSharingRepository: SettingsLibAudioSharingRepository,
             @Background backgroundDispatcher: CoroutineDispatcher,
         ): AudioSharingRepository =
-            if (Flags.enableLeAudioSharing() && localBluetoothManager != null) {
+            if (
+                (Flags.enableLeAudioSharing() || Flags.audioSharingDeveloperOption()) &&
+                    localBluetoothManager != null
+            ) {
                 AudioSharingRepositoryImpl(
                     localBluetoothManager,
                     settingsLibAudioSharingRepository,
@@ -72,7 +75,10 @@
             impl: Lazy<AudioSharingInteractorImpl>,
             emptyImpl: Lazy<AudioSharingInteractorEmptyImpl>,
         ): AudioSharingInteractor =
-            if (Flags.enableLeAudioSharing() && localBluetoothManager != null) {
+            if (
+                (Flags.enableLeAudioSharing() || Flags.audioSharingDeveloperOption()) &&
+                    localBluetoothManager != null
+            ) {
                 impl.get()
             } else {
                 emptyImpl.get()
@@ -85,7 +91,10 @@
             audioSharingImpl: Lazy<AudioSharingDeviceItemActionInteractorImpl>,
             impl: Lazy<DeviceItemActionInteractorImpl>,
         ): DeviceItemActionInteractor =
-            if (Flags.enableLeAudioSharing() && localBluetoothManager != null) {
+            if (
+                (Flags.enableLeAudioSharing() || Flags.audioSharingDeveloperOption()) &&
+                    localBluetoothManager != null
+            ) {
                 audioSharingImpl.get()
             } else {
                 impl.get()
@@ -97,7 +106,10 @@
             localBluetoothManager: LocalBluetoothManager?
         ): List<DeviceItemFactory> = buildList {
             add(ActiveMediaDeviceItemFactory())
-            if (Flags.enableLeAudioSharing() && localBluetoothManager != null) {
+            if (
+                (Flags.enableLeAudioSharing() || Flags.audioSharingDeveloperOption()) &&
+                    localBluetoothManager != null
+            ) {
                 add(AudioSharingMediaDeviceItemFactory(localBluetoothManager))
                 add(AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager))
             }
@@ -112,7 +124,10 @@
             localBluetoothManager: LocalBluetoothManager?
         ): List<DeviceItemType> = buildList {
             add(DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE)
-            if (Flags.enableLeAudioSharing() && localBluetoothManager != null) {
+            if (
+                (Flags.enableLeAudioSharing() || Flags.audioSharingDeveloperOption()) &&
+                    localBluetoothManager != null
+            ) {
                 add(DeviceItemType.AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE)
                 add(DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE)
             }
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt
index 79a11ee..ad49fd0 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt
@@ -17,11 +17,13 @@
 package com.android.systemui.bouncer.ui
 
 import android.content.Context
+import android.graphics.Typeface
 import android.util.AttributeSet
 import android.widget.LinearLayout
 import com.android.keyguard.BouncerKeyguardMessageArea
 import com.android.keyguard.KeyguardMessageArea
 import com.android.keyguard.KeyguardMessageAreaController
+import com.android.systemui.Flags
 import com.android.systemui.res.R
 
 class BouncerMessageView : LinearLayout {
@@ -37,10 +39,20 @@
     var secondaryMessageView: BouncerKeyguardMessageArea? = null
     var primaryMessage: KeyguardMessageAreaController<KeyguardMessageArea>? = null
     var secondaryMessage: KeyguardMessageAreaController<KeyguardMessageArea>? = null
+
     override fun onFinishInflate() {
         super.onFinishInflate()
         primaryMessageView = findViewById(R.id.bouncer_primary_message_area)
         secondaryMessageView = findViewById(R.id.bouncer_secondary_message_area)
+
+        if (Flags.gsfBouncer()) {
+            primaryMessageView?.apply {
+                typeface = Typeface.create("gsf-title-large-emphasized", Typeface.NORMAL)
+            }
+            secondaryMessageView?.apply {
+                typeface = Typeface.create("gsf-title-medium-emphasized", Typeface.NORMAL)
+            }
+        }
     }
 
     fun init(factory: KeyguardMessageAreaController.Factory) {
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt
index 12f06bb..8a4cc63 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt
@@ -3,6 +3,8 @@
 import android.view.ViewGroup
 import com.android.keyguard.KeyguardMessageAreaController
 import com.android.keyguard.dagger.KeyguardBouncerComponent
+import com.android.systemui.Flags.contAuthPlugin
+import com.android.systemui.biometrics.plugins.AuthContextPlugins
 import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlags
@@ -17,6 +19,7 @@
 import com.android.systemui.log.BouncerLogger
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import dagger.Lazy
+import java.util.Optional
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -60,6 +63,7 @@
 constructor(
     private val legacyBouncerDependencies: Lazy<LegacyBouncerDependencies>,
     private val composeBouncerDependencies: Lazy<ComposeBouncerDependencies>,
+    private val contextPlugins: Optional<AuthContextPlugins>,
 ) {
     fun bind(view: ViewGroup) {
         if (ComposeBouncerFlags.isOnlyComposeBouncerEnabled()) {
@@ -85,6 +89,7 @@
                 deps.bouncerMessageInteractor,
                 deps.bouncerLogger,
                 deps.selectedUserInteractor,
+                if (contAuthPlugin()) contextPlugins.orElse(null) else null,
             )
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
index 71eda0c..434a9ce 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
@@ -22,11 +22,13 @@
 import android.window.OnBackAnimationCallback
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.keyguard.KeyguardMessageAreaController
 import com.android.keyguard.KeyguardSecurityContainerController
 import com.android.keyguard.KeyguardSecurityModel
 import com.android.keyguard.KeyguardSecurityView
 import com.android.keyguard.dagger.KeyguardBouncerComponent
+import com.android.systemui.biometrics.plugins.AuthContextPlugins
 import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
 import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
 import com.android.systemui.bouncer.ui.BouncerViewDelegate
@@ -35,10 +37,10 @@
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.log.BouncerLogger
 import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.AuthContextPlugin
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import kotlinx.coroutines.awaitCancellation
 import kotlinx.coroutines.flow.filter
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 /** Binds the bouncer container to its view model. */
 object KeyguardBouncerViewBinder {
@@ -52,6 +54,7 @@
         bouncerMessageInteractor: BouncerMessageInteractor,
         bouncerLogger: BouncerLogger,
         selectedUserInteractor: SelectedUserInteractor,
+        plugins: AuthContextPlugins?,
     ) {
         // Builds the KeyguardSecurityContainerController from bouncer view group.
         val securityContainerController: KeyguardSecurityContainerController =
@@ -94,7 +97,7 @@
 
                 override fun setDismissAction(
                     onDismissAction: ActivityStarter.OnDismissAction?,
-                    cancelAction: Runnable?
+                    cancelAction: Runnable?,
                 ) {
                     securityContainerController.setOnDismissAction(onDismissAction, cancelAction)
                 }
@@ -138,7 +141,7 @@
                                     it.bindMessageView(
                                         bouncerMessageInteractor,
                                         messageAreaControllerFactory,
-                                        bouncerLogger
+                                        bouncerLogger,
                                     )
                                 }
                             } else {
@@ -149,6 +152,13 @@
                                 securityContainerController.reset()
                                 securityContainerController.onPause()
                             }
+                            plugins?.apply {
+                                if (isShowing) {
+                                    notifyBouncerShowing(view)
+                                } else {
+                                    notifyBouncerGone()
+                                }
+                            }
                         }
                     }
 
@@ -209,7 +219,7 @@
                             securityContainerController.showMessage(
                                 it.message,
                                 it.colorStateList,
-                                /* animated= */ true
+                                /* animated= */ true,
                             )
                             viewModel.onMessageShown()
                         }
@@ -233,8 +243,19 @@
                     awaitCancellation()
                 } finally {
                     viewModel.setBouncerViewDelegate(null)
+                    plugins?.notifyBouncerGone()
                 }
             }
         }
     }
 }
+
+private suspend fun AuthContextPlugins.notifyBouncerShowing(view: View) = use { plugin ->
+    plugin.onShowingSensitiveSurface(
+        AuthContextPlugin.SensitiveSurface.LockscreenBouncer(view = view)
+    )
+}
+
+private fun AuthContextPlugins.notifyBouncerGone() = useInBackground { plugin ->
+    plugin.onHidingSensitiveSurface(AuthContextPlugin.SensitiveSurface.LockscreenBouncer())
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModel.kt
index 47d91374..5deb751 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModel.kt
@@ -23,6 +23,7 @@
 import androidx.compose.ui.input.key.KeyEvent
 import androidx.compose.ui.input.key.type
 import androidx.core.graphics.drawable.toBitmap
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.app.tracing.coroutines.traceCoroutine
 import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
 import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
@@ -35,6 +36,7 @@
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.common.shared.model.Text
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardMediaKeyInteractor
 import com.android.systemui.lifecycle.ExclusiveActivatable
 import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
@@ -48,7 +50,6 @@
 import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.map
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 /** Models UI state for the content of the bouncer scene. */
 class BouncerSceneContentViewModel
@@ -67,6 +68,7 @@
     private val bouncerHapticPlayer: BouncerHapticPlayer,
     private val keyguardMediaKeyInteractor: KeyguardMediaKeyInteractor,
     private val bouncerActionButtonInteractor: BouncerActionButtonInteractor,
+    private val keyguardDismissActionInteractor: KeyguardDismissActionInteractor,
 ) : ExclusiveActivatable() {
     private val _selectedUserImage = MutableStateFlow<Bitmap?>(null)
     val selectedUserImage: StateFlow<Bitmap?> = _selectedUserImage.asStateFlow()
@@ -421,6 +423,13 @@
         }
     }
 
+    /**
+     * Notifies that the bouncer UI has been destroyed (e.g. the composable left the composition).
+     */
+    fun onUiDestroyed() {
+        keyguardDismissActionInteractor.clearDismissAction()
+    }
+
     data class DialogViewModel(
         val text: String,
 
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
index ccd953d..6f2a2c4 100644
--- a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
+++ b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.brightness.ui.compose
 
+import android.view.MotionEvent
 import androidx.compose.animation.core.animateFloatAsState
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.gestures.Orientation
@@ -32,6 +33,7 @@
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
@@ -41,6 +43,7 @@
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.geometry.Size
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.input.pointer.pointerInteropFilter
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.colorResource
 import androidx.compose.ui.res.stringResource
@@ -103,11 +106,11 @@
             null
         }
 
-    val overriddenByAppState =
+    val overriddenByAppState by
         if (Flags.showToastWhenAppControlBrightness()) {
-            viewModel.brightnessOverriddenByWindow.collectAsStateWithLifecycle().value
+            viewModel.brightnessOverriddenByWindow.collectAsStateWithLifecycle()
         } else {
-            false
+            remember { mutableStateOf(false) }
         }
 
     PlatformSlider(
@@ -221,7 +224,16 @@
                     )
                     .then(if (viewModel.showMirror) Modifier.drawInOverlay() else Modifier)
                     .sliderBackground(containerColor)
-                    .fillMaxWidth(),
+                    .fillMaxWidth()
+                    .pointerInteropFilter {
+                        if (
+                            it.actionMasked == MotionEvent.ACTION_UP ||
+                                it.actionMasked == MotionEvent.ACTION_CANCEL
+                        ) {
+                            viewModel.emitBrightnessTouchForFalsing()
+                        }
+                        false
+                    },
             formatter = viewModel::formatValue,
             hapticsViewModelFactory = viewModel.hapticsViewModelFactory,
         )
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModel.kt
index 1630ee5..7df7155 100644
--- a/packages/SystemUI/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModel.kt
@@ -16,12 +16,14 @@
 
 package com.android.systemui.brightness.ui.viewmodel
 
-import androidx.compose.runtime.getValue
 import android.content.Context
 import androidx.annotation.StringRes
+import androidx.compose.runtime.getValue
 import com.android.systemui.brightness.domain.interactor.BrightnessPolicyEnforcementInteractor
 import com.android.systemui.brightness.domain.interactor.ScreenBrightnessInteractor
 import com.android.systemui.brightness.shared.model.GammaBrightness
+import com.android.systemui.classifier.Classifier
+import com.android.systemui.classifier.domain.interactor.FalsingInteractor
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.common.shared.model.Text
@@ -52,6 +54,7 @@
     private val brightnessPolicyEnforcementInteractor: BrightnessPolicyEnforcementInteractor,
     val hapticsViewModelFactory: SliderHapticsViewModel.Factory,
     private val brightnessMirrorShowingInteractor: BrightnessMirrorShowingInteractor,
+    private val falsingInteractor: FalsingInteractor,
     @Assisted private val supportsMirroring: Boolean,
     private val brightnessWarningToast: BrightnessWarningToast,
 ) : ExclusiveActivatable() {
@@ -87,6 +90,10 @@
         brightnessWarningToast.show(viewContext, resId)
     }
 
+    fun emitBrightnessTouchForFalsing() {
+        falsingInteractor.isFalseTouch(Classifier.BRIGHTNESS_SLIDER)
+    }
+
     /**
      * As a brightness slider is dragged, the corresponding events should be sent using this method.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/domain/interactor/FalsingInteractor.kt b/packages/SystemUI/src/com/android/systemui/classifier/domain/interactor/FalsingInteractor.kt
index 57e9ade..074b64e 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/domain/interactor/FalsingInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/classifier/domain/interactor/FalsingInteractor.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.classifier.FalsingCollectorActual
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.FalsingManager.Penalty
 import javax.inject.Inject
 
 /**
@@ -63,12 +64,13 @@
      * Inserts the given [result] into the falsing system, affecting future runs of the classifier
      * as if this was a result that had organically happened before.
      */
-    fun updateFalseConfidence(
-        result: FalsingClassifier.Result,
-    ) = collector.updateFalseConfidence(result)
+    fun updateFalseConfidence(result: FalsingClassifier.Result) =
+        collector.updateFalseConfidence(result)
 
     /** Returns `true` if the gesture should be rejected. */
-    fun isFalseTouch(
-        @Classifier.InteractionType interactionType: Int,
-    ): Boolean = manager.isFalseTouch(interactionType)
+    fun isFalseTouch(@Classifier.InteractionType interactionType: Int): Boolean =
+        manager.isFalseTouch(interactionType)
+
+    /** Returns `true` if the tap gesture should be rejected */
+    fun isFalseTap(@Penalty penalty: Int): Boolean = manager.isFalseTap(penalty)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java b/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
index 7fe0032..82bce0b 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
@@ -179,6 +179,14 @@
     }
 
     /**
+     * Only for testing. Get mSeekBarListener to the seekbar.
+     */
+    @VisibleForTesting
+    public SeekBarChangeListener getSeekBarChangeListener() {
+        return mSeekBarListener;
+    }
+
+    /**
      * Only for testing. Get {@link #mSeekbar} in the layout.
      */
     @VisibleForTesting
@@ -289,8 +297,10 @@
         void onUserInteractionFinalized(SeekBar seekBar, @ControlUnitType int control);
     }
 
-    private class SeekBarChangeListener implements SeekBar.OnSeekBarChangeListener {
+    @VisibleForTesting
+    public class SeekBarChangeListener implements SeekBar.OnSeekBarChangeListener {
         private OnSeekBarWithIconButtonsChangeListener mOnSeekBarChangeListener = null;
+        private boolean mSeekByTouch = false;
 
         @Override
         public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
@@ -308,6 +318,14 @@
                             seekBar, OnSeekBarWithIconButtonsChangeListener.ControlUnitType.BUTTON);
                 } else {
                     mOnSeekBarChangeListener.onProgressChanged(seekBar, progress, fromUser);
+                    if (!mSeekByTouch) {
+                        // Accessibility users could change the progress of the seekbar without
+                        // touching the seekbar or clicking the buttons. We will consider the
+                        // interaction has finished in this case.
+                        mOnSeekBarChangeListener.onUserInteractionFinalized(
+                                seekBar,
+                                OnSeekBarWithIconButtonsChangeListener.ControlUnitType.SLIDER);
+                    }
                 }
             }
             updateIconViewIfNeeded(progress);
@@ -315,6 +333,7 @@
 
         @Override
         public void onStartTrackingTouch(SeekBar seekBar) {
+            mSeekByTouch = true;
             if (mOnSeekBarChangeListener != null) {
                 mOnSeekBarChangeListener.onStartTrackingTouch(seekBar);
             }
@@ -322,6 +341,7 @@
 
         @Override
         public void onStopTrackingTouch(SeekBar seekBar) {
+            mSeekByTouch = false;
             if (mOnSeekBarChangeListener != null) {
                 mOnSeekBarChangeListener.onStopTrackingTouch(seekBar);
                 mOnSeekBarChangeListener.onUserInteractionFinalized(
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index db9a7f5..d648b9c 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -23,6 +23,7 @@
 import com.android.compose.animation.scene.TransitionKey
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.CoreStartable
+import com.android.systemui.Flags.communalHubOnMobile
 import com.android.systemui.Flags.communalSceneKtfRefactor
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
@@ -216,6 +217,9 @@
                         communalSceneInteractor.changeScene(
                             newScene = CommunalScenes.Blank,
                             loggingReason = "hub timeout",
+                            transitionKey =
+                                if (communalHubOnMobile()) CommunalTransitionKeys.SimpleFade
+                                else null,
                         )
                         uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT)
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
index 44dd34a..8ddd1ed 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
@@ -34,6 +34,7 @@
 import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper
 import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelperImpl
+import com.android.systemui.communal.ui.compose.sceneTransitions
 import com.android.systemui.communal.util.CommunalColors
 import com.android.systemui.communal.util.CommunalColorsImpl
 import com.android.systemui.communal.widgets.CommunalWidgetModule
@@ -113,6 +114,7 @@
                 SceneContainerConfig(
                     sceneKeys = listOf(CommunalScenes.Blank, CommunalScenes.Communal),
                     initialSceneKey = CommunalScenes.Blank,
+                    transitions = sceneTransitions,
                     navigationDistances =
                         mapOf(CommunalScenes.Blank to 0, CommunalScenes.Communal to 1),
                 )
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt
index 7b54815..26abb48 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt
@@ -20,9 +20,11 @@
 import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL
 import android.content.IntentFilter
 import android.content.pm.UserInfo
+import android.content.res.Resources
 import android.os.UserHandle
 import android.provider.Settings
 import com.android.systemui.Flags.communalHub
+import com.android.systemui.Flags.glanceableHubV2
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.communal.data.model.CommunalEnabledState
 import com.android.systemui.communal.data.model.DisabledReason
@@ -33,6 +35,7 @@
 import com.android.systemui.communal.shared.model.CommunalBackgroundType
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.flags.FeatureFlagsClassic
 import com.android.systemui.flags.Flags
 import com.android.systemui.util.kotlin.emitOnStart
@@ -53,13 +56,30 @@
     fun getEnabledState(user: UserInfo): Flow<CommunalEnabledState>
 
     /**
-     * Returns true if both the communal trunk-stable flag and resource flag are enabled.
+     * Returns true if any glanceable hub functionality should be enabled via configs and flags.
      *
-     * The trunk-stable flag is controlled by server rollout and is on all devices. The resource
-     * flag is enabled via resource overlay only on products we want the hub to be present on.
+     * This should be used for preventing basic glanceable hub functionality from running on devices
+     * that don't need it.
+     *
+     * If the glanceable_hub_v2 flag is enabled, checks the config_glanceableHubEnabled Android
+     * config boolean. Otherwise, checks the old config_communalServiceEnabled config and
+     * communal_hub flag.
      */
     fun getFlagEnabled(): Boolean
 
+    /**
+     * Returns true if the Android config config_glanceableHubEnabled and the glanceable_hub_v2 flag
+     * are enabled.
+     *
+     * This should be used to flag off new glanceable hub or dream behavior that should launch
+     * together with the new hub experience that brings the hub to mobile.
+     *
+     * The trunk-stable flag is controlled by server rollout and is on all devices. The Android
+     * config flag is enabled via resource overlay only on products we want the hub to be present
+     * on.
+     */
+    fun getV2FlagEnabled(): Boolean
+
     /** Keyguard widgets enabled state by Device Policy Manager for the specified user. */
     fun getAllowedByDevicePolicy(user: UserInfo): Flow<Boolean>
 
@@ -72,6 +92,7 @@
 @Inject
 constructor(
     @Background private val bgDispatcher: CoroutineDispatcher,
+    @Main private val resources: Resources,
     private val featureFlagsClassic: FeatureFlagsClassic,
     private val secureSettings: SecureSettings,
     private val broadcastDispatcher: BroadcastDispatcher,
@@ -79,7 +100,18 @@
 ) : CommunalSettingsRepository {
 
     override fun getFlagEnabled(): Boolean {
-        return featureFlagsClassic.isEnabled(Flags.COMMUNAL_SERVICE_ENABLED) && communalHub()
+        return if (getV2FlagEnabled()) {
+            true
+        } else {
+            // This config (exposed as a classic feature flag) is targeted only to tablet.
+            // TODO(b/379181581): clean up usages of communal_hub flag
+            featureFlagsClassic.isEnabled(Flags.COMMUNAL_SERVICE_ENABLED) && communalHub()
+        }
+    }
+
+    override fun getV2FlagEnabled(): Boolean {
+        return resources.getBoolean(com.android.internal.R.bool.config_glanceableHubEnabled) &&
+            glanceableHubV2()
     }
 
     override fun getEnabledState(user: UserInfo): Flow<CommunalEnabledState> {
@@ -128,7 +160,7 @@
                     secureSettings.getIntForUser(
                         GLANCEABLE_HUB_BACKGROUND_SETTING,
                         CommunalBackgroundType.ANIMATED.value,
-                        user.id
+                        user.id,
                     )
                 CommunalBackgroundType.entries.find { type -> type.value == intType }
                     ?: CommunalBackgroundType.ANIMATED
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
index 5ecf2e6b..a339af3 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
@@ -195,7 +195,7 @@
     open fun onDismissCtaTile() {}
 
     /** Called as the user starts dragging a widget to reorder. */
-    open fun onReorderWidgetStart() {}
+    open fun onReorderWidgetStart(draggingItemKey: String) {}
 
     /** Called as the user finishes dragging a widget to reorder. */
     open fun onReorderWidgetEnd() {}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
index 736ed5c..52bf000 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
@@ -164,9 +164,8 @@
         )
     }
 
-    override fun onReorderWidgetStart() {
-        // Clear selection status
-        setSelectedKey(null)
+    override fun onReorderWidgetStart(draggingItemKey: String) {
+        setSelectedKey(draggingItemKey)
         _reorderingWidgets.value = true
         uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_START)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt b/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
index cc6007b..50d86a2 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
@@ -20,6 +20,7 @@
 import android.os.Bundle
 import android.util.SizeF
 import com.android.app.tracing.coroutines.withContextTraced as withContext
+import com.android.systemui.Flags
 import com.android.systemui.communal.domain.model.CommunalContentModel
 import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper
 import com.android.systemui.communal.widgets.AppWidgetHostListenerDelegate
@@ -30,6 +31,9 @@
 import com.android.systemui.dagger.qualifiers.UiBackground
 import dagger.Lazy
 import java.util.concurrent.Executor
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.concurrent.ThreadPoolExecutor
+import java.util.concurrent.TimeUnit
 import javax.inject.Inject
 import kotlin.coroutines.CoroutineContext
 
@@ -53,7 +57,11 @@
         withContext("$TAG#createWidget", uiBgContext) {
             val view =
                 CommunalAppWidgetHostView(context, interactionHandler).apply {
-                    setExecutor(uiBgExecutor)
+                    if (Flags.communalHubUseThreadPoolForWidgets()) {
+                        setExecutor(widgetExecutor)
+                    } else {
+                        setExecutor(uiBgExecutor)
+                    }
                     setAppWidget(model.appWidgetId, model.providerInfo)
                 }
 
@@ -90,5 +98,20 @@
 
     private companion object {
         const val TAG = "WidgetViewFactory"
+
+        val poolSize = Runtime.getRuntime().availableProcessors().coerceAtLeast(2)
+
+        /**
+         * This executor is used for widget inflation. Parameters match what launcher uses. See
+         * [com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR].
+         */
+        val widgetExecutor =
+            ThreadPoolExecutor(
+                /*corePoolSize*/ poolSize,
+                /*maxPoolSize*/ poolSize,
+                /*keepAlive*/ 1,
+                /*unit*/ TimeUnit.SECONDS,
+                /*workQueue*/ LinkedBlockingQueue(),
+            )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
index 41edb4a..740e011 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.controls.management
 
+import android.app.Activity
 import android.app.ActivityOptions
 import android.content.ComponentName
 import android.content.Context
@@ -34,25 +35,25 @@
 import androidx.recyclerview.widget.GridLayoutManager
 import androidx.recyclerview.widget.ItemTouchHelper
 import androidx.recyclerview.widget.RecyclerView
-import com.android.systemui.res.R
 import com.android.systemui.controls.CustomIconCache
 import com.android.systemui.controls.controller.ControlsControllerImpl
 import com.android.systemui.controls.controller.StructureInfo
 import com.android.systemui.controls.ui.ControlsActivity
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
 import java.util.concurrent.Executor
 import javax.inject.Inject
 
-/**
- * Activity for rearranging and removing controls for a given structure
- */
-open class ControlsEditingActivity @Inject constructor(
+/** Activity for rearranging and removing controls for a given structure */
+open class ControlsEditingActivity
+@Inject
+constructor(
     @Main private val mainExecutor: Executor,
     private val controller: ControlsControllerImpl,
     private val userTracker: UserTracker,
     private val customIconCache: CustomIconCache,
-) : ComponentActivity() {
+) : ComponentActivity(), ControlsManagementActivity {
 
     companion object {
         private const val DEBUG = false
@@ -64,6 +65,9 @@
         private val EMPTY_TEXT_ID = R.string.controls_favorite_removed
     }
 
+    override val activity: Activity
+        get() = this
+
     private lateinit var component: ComponentName
     private lateinit var structure: CharSequence
     private lateinit var model: FavoritesModel
@@ -73,16 +77,17 @@
 
     private var isFromFavoriting: Boolean = false
 
-    private val userTrackerCallback: UserTracker.Callback = object : UserTracker.Callback {
-        private val startingUser = controller.currentUserId
+    private val userTrackerCallback: UserTracker.Callback =
+        object : UserTracker.Callback {
+            private val startingUser = controller.currentUserId
 
-        override fun onUserChanged(newUser: Int, userContext: Context) {
-            if (newUser != startingUser) {
-                userTracker.removeCallback(this)
-                finish()
+            override fun onUserChanged(newUser: Int, userContext: Context) {
+                if (newUser != startingUser) {
+                    userTracker.removeCallback(this)
+                    finish()
+                }
             }
         }
-    }
 
     private val mOnBackInvokedCallback = OnBackInvokedCallback {
         if (DEBUG) {
@@ -98,9 +103,7 @@
             component = it
         } ?: run(this::finish)
         isFromFavoriting = intent.getBooleanExtra(EXTRA_FROM_FAVORITING, false)
-        intent.getCharSequenceExtra(EXTRA_STRUCTURE)?.let {
-            structure = it
-        } ?: run(this::finish)
+        intent.getCharSequenceExtra(EXTRA_STRUCTURE)?.let { structure = it } ?: run(this::finish)
 
         bindViews()
 
@@ -117,7 +120,9 @@
             Log.d(TAG, "Registered onBackInvokedCallback")
         }
         onBackInvokedDispatcher.registerOnBackInvokedCallback(
-                OnBackInvokedDispatcher.PRIORITY_DEFAULT, mOnBackInvokedCallback)
+            OnBackInvokedDispatcher.PRIORITY_DEFAULT,
+            mOnBackInvokedCallback,
+        )
     }
 
     override fun onStop() {
@@ -142,18 +147,21 @@
                     override fun run() {
                         finish()
                     }
-                }
-        ).start()
+                },
+            )
+            .start()
     }
 
     private fun bindViews() {
         setContentView(R.layout.controls_management)
 
+        applyInsets(R.id.controls_management_root)
+
         lifecycle.addObserver(
             ControlsAnimations.observerForAnimations(
                 requireViewById<ViewGroup>(R.id.controls_management_root),
                 window,
-                intent
+                intent,
             )
         )
 
@@ -163,126 +171,142 @@
         }
         requireViewById<TextView>(R.id.title).text = structure
         setTitle(structure)
-        subtitle = requireViewById<TextView>(R.id.subtitle).apply {
-            setText(SUBTITLE_ID)
-        }
+        subtitle = requireViewById<TextView>(R.id.subtitle).apply { setText(SUBTITLE_ID) }
     }
 
     private fun bindButtons() {
-        addControls = requireViewById<Button>(R.id.addControls).apply {
-            isEnabled = true
-            visibility = View.VISIBLE
-            setOnClickListener {
-                if (saveButton.isEnabled) {
-                    // The user has made changes
-                    Toast.makeText(
-                        applicationContext,
-                        R.string.controls_favorite_toast_no_changes,
-                        Toast.LENGTH_SHORT
-                    ).show()
+        addControls =
+            requireViewById<Button>(R.id.addControls).apply {
+                isEnabled = true
+                visibility = View.VISIBLE
+                setOnClickListener {
+                    if (saveButton.isEnabled) {
+                        // The user has made changes
+                        Toast.makeText(
+                                applicationContext,
+                                R.string.controls_favorite_toast_no_changes,
+                                Toast.LENGTH_SHORT,
+                            )
+                            .show()
+                    }
+                    if (isFromFavoriting) {
+                        animateExitAndFinish()
+                    } else {
+                        startActivity(
+                            Intent(context, ControlsFavoritingActivity::class.java).also {
+                                it.putExtra(ControlsFavoritingActivity.EXTRA_STRUCTURE, structure)
+                                it.putExtra(Intent.EXTRA_COMPONENT_NAME, component)
+                                it.putExtra(
+                                    ControlsFavoritingActivity.EXTRA_APP,
+                                    intent.getCharSequenceExtra(EXTRA_APP),
+                                )
+                                it.putExtra(
+                                    ControlsFavoritingActivity.EXTRA_SOURCE,
+                                    ControlsFavoritingActivity.EXTRA_SOURCE_VALUE_FROM_EDITING,
+                                )
+                            },
+                            ActivityOptions.makeSceneTransitionAnimation(
+                                    this@ControlsEditingActivity
+                                )
+                                .toBundle(),
+                        )
+                    }
                 }
-                if (isFromFavoriting) {
-                    animateExitAndFinish()
-                } else {
-                    startActivity(Intent(context, ControlsFavoritingActivity::class.java).also {
-                        it.putExtra(ControlsFavoritingActivity.EXTRA_STRUCTURE, structure)
-                        it.putExtra(Intent.EXTRA_COMPONENT_NAME, component)
-                        it.putExtra(
-                            ControlsFavoritingActivity.EXTRA_APP,
-                            intent.getCharSequenceExtra(EXTRA_APP),
-                        )
-                        it.putExtra(
-                            ControlsFavoritingActivity.EXTRA_SOURCE,
-                            ControlsFavoritingActivity.EXTRA_SOURCE_VALUE_FROM_EDITING,
-                        )
-                    },
-                                  ActivityOptions.makeSceneTransitionAnimation(
-                                      this@ControlsEditingActivity
-                                  ).toBundle(),
+            }
+        saveButton =
+            requireViewById<Button>(R.id.done).apply {
+                isEnabled = isFromFavoriting
+                setText(R.string.save)
+                setOnClickListener {
+                    saveFavorites()
+                    startActivity(
+                        Intent(applicationContext, ControlsActivity::class.java),
+                        ActivityOptions.makeSceneTransitionAnimation(this@ControlsEditingActivity)
+                            .toBundle(),
                     )
+                    animateExitAndFinish()
                 }
             }
-        }
-        saveButton = requireViewById<Button>(R.id.done).apply {
-            isEnabled = isFromFavoriting
-            setText(R.string.save)
-            setOnClickListener {
-                saveFavorites()
-                startActivity(
-                    Intent(applicationContext, ControlsActivity::class.java),
-                    ActivityOptions
-                        .makeSceneTransitionAnimation(this@ControlsEditingActivity).toBundle()
-                )
-                animateExitAndFinish()
-            }
-        }
     }
 
     private fun saveFavorites() {
         controller.replaceFavoritesForStructure(
-                StructureInfo(component, structure, model.favorites))
+            StructureInfo(component, structure, model.favorites)
+        )
     }
 
-    private val favoritesModelCallback = object : FavoritesModel.FavoritesModelCallback {
-        override fun onNoneChanged(showNoFavorites: Boolean) {
-            if (showNoFavorites) {
-                subtitle.setText(EMPTY_TEXT_ID)
-            } else {
-                subtitle.setText(SUBTITLE_ID)
+    private val favoritesModelCallback =
+        object : FavoritesModel.FavoritesModelCallback {
+            override fun onNoneChanged(showNoFavorites: Boolean) {
+                if (showNoFavorites) {
+                    subtitle.setText(EMPTY_TEXT_ID)
+                } else {
+                    subtitle.setText(SUBTITLE_ID)
+                }
+            }
+
+            override fun onChange() = Unit
+
+            override fun onFirstChange() {
+                saveButton.isEnabled = true
             }
         }
 
-        override fun onChange() = Unit
-
-        override fun onFirstChange() {
-            saveButton.isEnabled = true
-        }
-    }
-
     private fun setUpList() {
         val controls = controller.getFavoritesForStructure(component, structure)
         model = FavoritesModel(customIconCache, component, controls, favoritesModelCallback)
         val elevation = resources.getFloat(R.dimen.control_card_elevation)
         val recyclerView = requireViewById<RecyclerView>(R.id.list)
         recyclerView.alpha = 0.0f
-        val adapter = ControlAdapter(elevation, userTracker.userId).apply {
-            registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
-                var hasAnimated = false
-                override fun onChanged() {
-                    if (!hasAnimated) {
-                        hasAnimated = true
-                        ControlsAnimations.enterAnimation(recyclerView).start()
-                    }
-                }
-            })
-        }
+        val adapter =
+            ControlAdapter(elevation, userTracker.userId).apply {
+                registerAdapterDataObserver(
+                    object : RecyclerView.AdapterDataObserver() {
+                        var hasAnimated = false
 
-        val margin = resources
-                .getDimensionPixelSize(R.dimen.controls_card_margin)
+                        override fun onChanged() {
+                            if (!hasAnimated) {
+                                hasAnimated = true
+                                ControlsAnimations.enterAnimation(recyclerView).start()
+                            }
+                        }
+                    }
+                )
+            }
+
+        val margin = resources.getDimensionPixelSize(R.dimen.controls_card_margin)
         val itemDecorator = MarginItemDecorator(margin, margin)
         val spanCount = ControlAdapter.findMaxColumns(resources)
 
         recyclerView.apply {
             this.adapter = adapter
-            layoutManager = object : GridLayoutManager(recyclerView.context, spanCount) {
+            layoutManager =
+                object : GridLayoutManager(recyclerView.context, spanCount) {
 
-                // This will remove from the announcement the row corresponding to the divider,
-                // as it's not something that should be announced.
-                override fun getRowCountForAccessibility(
-                    recycler: RecyclerView.Recycler,
-                    state: RecyclerView.State
-                ): Int {
-                    val initial = super.getRowCountForAccessibility(recycler, state)
-                    return if (initial > 0) initial - 1 else initial
-                }
-            }.apply {
-                spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
-                    override fun getSpanSize(position: Int): Int {
-                        return if (adapter?.getItemViewType(position)
-                                != ControlAdapter.TYPE_CONTROL) spanCount else 1
+                        // This will remove from the announcement the row corresponding to the
+                        // divider,
+                        // as it's not something that should be announced.
+                        override fun getRowCountForAccessibility(
+                            recycler: RecyclerView.Recycler,
+                            state: RecyclerView.State,
+                        ): Int {
+                            val initial = super.getRowCountForAccessibility(recycler, state)
+                            return if (initial > 0) initial - 1 else initial
+                        }
                     }
-                }
-            }
+                    .apply {
+                        spanSizeLookup =
+                            object : GridLayoutManager.SpanSizeLookup() {
+                                override fun getSpanSize(position: Int): Int {
+                                    return if (
+                                        adapter?.getItemViewType(position) !=
+                                            ControlAdapter.TYPE_CONTROL
+                                    )
+                                        spanCount
+                                    else 1
+                                }
+                            }
+                    }
             addItemDecoration(itemDecorator)
         }
         adapter.changeModel(model)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index 2ea4303..ab55c53 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -18,6 +18,7 @@
 
 import android.animation.Animator
 import android.animation.AnimatorListenerAdapter
+import android.app.Activity
 import android.app.ActivityOptions
 import android.content.ComponentName
 import android.content.Context
@@ -39,22 +40,24 @@
 import androidx.annotation.VisibleForTesting
 import androidx.viewpager2.widget.ViewPager2
 import com.android.systemui.Prefs
-import com.android.systemui.res.R
 import com.android.systemui.controls.TooltipManager
 import com.android.systemui.controls.controller.ControlsControllerImpl
 import com.android.systemui.controls.controller.StructureInfo
 import com.android.systemui.controls.ui.ControlsActivity
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
 import java.text.Collator
 import java.util.concurrent.Executor
 import javax.inject.Inject
 
-open class ControlsFavoritingActivity @Inject constructor(
+open class ControlsFavoritingActivity
+@Inject
+constructor(
     @Main private val executor: Executor,
     private val controller: ControlsControllerImpl,
     private val userTracker: UserTracker,
-) : ComponentActivity() {
+) : ComponentActivity(), ControlsManagementActivity {
 
     companion object {
         private const val DEBUG = false
@@ -74,6 +77,9 @@
         private const val TOOLTIP_MAX_SHOWN = 2
     }
 
+    override val activity: Activity
+        get() = this
+
     private var component: ComponentName? = null
     private var appName: CharSequence? = null
     private var structureExtra: CharSequence? = null
@@ -95,18 +101,21 @@
 
     private val fromProviderSelector: Boolean
         get() = openSource == EXTRA_SOURCE_VALUE_FROM_PROVIDER_SELECTOR
+
     private val fromEditing: Boolean
         get() = openSource == EXTRA_SOURCE_VALUE_FROM_EDITING
-    private val userTrackerCallback: UserTracker.Callback = object : UserTracker.Callback {
-        private val startingUser = controller.currentUserId
 
-        override fun onUserChanged(newUser: Int, userContext: Context) {
-            if (newUser != startingUser) {
-                userTracker.removeCallback(this)
-                finish()
+    private val userTrackerCallback: UserTracker.Callback =
+        object : UserTracker.Callback {
+            private val startingUser = controller.currentUserId
+
+            override fun onUserChanged(newUser: Int, userContext: Context) {
+                if (newUser != startingUser) {
+                    userTracker.removeCallback(this)
+                    finish()
+                }
             }
         }
-    }
 
     private val mOnBackInvokedCallback = OnBackInvokedCallback {
         if (DEBUG) {
@@ -138,81 +147,113 @@
         bindViews()
     }
 
-    private val controlsModelCallback = object : ControlsModel.ControlsModelCallback {
-        override fun onFirstChange() {
-            doneButton.isEnabled = true
-        }
+    private val controlsModelCallback =
+        object : ControlsModel.ControlsModelCallback {
+            override fun onFirstChange() {
+                doneButton.isEnabled = true
+            }
 
-        override fun onChange() {
-            val structure: StructureContainer = listOfStructures[structurePager.currentItem]
-            rearrangeButton.isEnabled = structure.model.favorites.isNotEmpty()
+            override fun onChange() {
+                val structure: StructureContainer = listOfStructures[structurePager.currentItem]
+                rearrangeButton.isEnabled = structure.model.favorites.isNotEmpty()
+            }
         }
-    }
 
     private fun loadControls() {
         component?.let { componentName ->
             statusText.text = resources.getText(com.android.internal.R.string.loading)
-            val emptyZoneString = resources.getText(
-                    R.string.controls_favorite_other_zone_header)
-            controller.loadForComponent(componentName, { data ->
-                val allControls = data.allControls
-                val favoriteKeys = data.favoritesIds
-                val error = data.errorOnLoad
-                val controlsByStructure = allControls.groupBy { it.control.structure ?: "" }
-                listOfStructures = controlsByStructure.map {
-                    StructureContainer(it.key, AllModel(
-                            it.value, favoriteKeys, emptyZoneString, controlsModelCallback))
-                }.sortedWith(comparator)
+            val emptyZoneString = resources.getText(R.string.controls_favorite_other_zone_header)
+            controller.loadForComponent(
+                componentName,
+                { data ->
+                    val allControls = data.allControls
+                    val favoriteKeys = data.favoritesIds
+                    val error = data.errorOnLoad
+                    val controlsByStructure = allControls.groupBy { it.control.structure ?: "" }
+                    listOfStructures =
+                        controlsByStructure
+                            .map {
+                                StructureContainer(
+                                    it.key,
+                                    AllModel(
+                                        it.value,
+                                        favoriteKeys,
+                                        emptyZoneString,
+                                        controlsModelCallback,
+                                    ),
+                                )
+                            }
+                            .sortedWith(comparator)
 
-                val structureIndex = listOfStructures.indexOfFirst {
-                    sc -> sc.structureName == structureExtra
-                }.let { if (it == -1) 0 else it }
+                    val structureIndex =
+                        listOfStructures
+                            .indexOfFirst { sc -> sc.structureName == structureExtra }
+                            .let { if (it == -1) 0 else it }
 
-                // If we were requested to show a single structure, set the list to just that one
-                if (intent.getBooleanExtra(EXTRA_SINGLE_STRUCTURE, false)) {
-                    listOfStructures = listOf(listOfStructures[structureIndex])
-                }
-
-                executor.execute {
-                    structurePager.adapter = StructureAdapter(listOfStructures, userTracker.userId)
-                    structurePager.setCurrentItem(structureIndex)
-                    if (error) {
-                        statusText.text = resources.getString(R.string.controls_favorite_load_error,
-                                appName ?: "")
-                        subtitleView.visibility = View.GONE
-                    } else if (listOfStructures.isEmpty()) {
-                        statusText.text = resources.getString(R.string.controls_favorite_load_none)
-                        subtitleView.visibility = View.GONE
-                    } else {
-                        statusText.visibility = View.GONE
-
-                        pageIndicator.setNumPages(listOfStructures.size)
-                        pageIndicator.setLocation(0f)
-                        pageIndicator.visibility =
-                            if (listOfStructures.size > 1) View.VISIBLE else View.INVISIBLE
-
-                        ControlsAnimations.enterAnimation(pageIndicator).apply {
-                            addListener(object : AnimatorListenerAdapter() {
-                                override fun onAnimationEnd(animation: Animator) {
-                                    // Position the tooltip if necessary after animations are complete
-                                    // so we can get the position on screen. The tooltip is not
-                                    // rooted in the layout root.
-                                    if (pageIndicator.visibility == View.VISIBLE &&
-                                        mTooltipManager != null) {
-                                        val p = IntArray(2)
-                                        pageIndicator.getLocationOnScreen(p)
-                                        val x = p[0] + pageIndicator.width / 2
-                                        val y = p[1] + pageIndicator.height
-                                        mTooltipManager?.show(
-                                            R.string.controls_structure_tooltip, x, y)
-                                    }
-                                }
-                            })
-                        }.start()
-                        ControlsAnimations.enterAnimation(structurePager).start()
+                    // If we were requested to show a single structure, set the list to just that
+                    // one
+                    if (intent.getBooleanExtra(EXTRA_SINGLE_STRUCTURE, false)) {
+                        listOfStructures = listOf(listOfStructures[structureIndex])
                     }
-                }
-            }, { runnable -> cancelLoadRunnable = runnable })
+
+                    executor.execute {
+                        structurePager.adapter =
+                            StructureAdapter(listOfStructures, userTracker.userId)
+                        structurePager.setCurrentItem(structureIndex)
+                        if (error) {
+                            statusText.text =
+                                resources.getString(
+                                    R.string.controls_favorite_load_error,
+                                    appName ?: "",
+                                )
+                            subtitleView.visibility = View.GONE
+                        } else if (listOfStructures.isEmpty()) {
+                            statusText.text =
+                                resources.getString(R.string.controls_favorite_load_none)
+                            subtitleView.visibility = View.GONE
+                        } else {
+                            statusText.visibility = View.GONE
+
+                            pageIndicator.setNumPages(listOfStructures.size)
+                            pageIndicator.setLocation(0f)
+                            pageIndicator.visibility =
+                                if (listOfStructures.size > 1) View.VISIBLE else View.INVISIBLE
+
+                            ControlsAnimations.enterAnimation(pageIndicator)
+                                .apply {
+                                    addListener(
+                                        object : AnimatorListenerAdapter() {
+                                            override fun onAnimationEnd(animation: Animator) {
+                                                // Position the tooltip if necessary after
+                                                // animations are complete
+                                                // so we can get the position on screen. The tooltip
+                                                // is not
+                                                // rooted in the layout root.
+                                                if (
+                                                    pageIndicator.visibility == View.VISIBLE &&
+                                                        mTooltipManager != null
+                                                ) {
+                                                    val p = IntArray(2)
+                                                    pageIndicator.getLocationOnScreen(p)
+                                                    val x = p[0] + pageIndicator.width / 2
+                                                    val y = p[1] + pageIndicator.height
+                                                    mTooltipManager?.show(
+                                                        R.string.controls_structure_tooltip,
+                                                        x,
+                                                        y,
+                                                    )
+                                                }
+                                            }
+                                        }
+                                    )
+                                }
+                                .start()
+                            ControlsAnimations.enterAnimation(structurePager).start()
+                        }
+                    }
+                },
+                { runnable -> cancelLoadRunnable = runnable },
+            )
         }
     }
 
@@ -221,35 +262,39 @@
         pageIndicator.alpha = 0.0f
         structurePager.apply {
             adapter = StructureAdapter(emptyList(), userTracker.userId)
-            registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
-                override fun onPageSelected(position: Int) {
-                    super.onPageSelected(position)
-                    val name = listOfStructures[position].structureName
-                    val title = if (!TextUtils.isEmpty(name)) name else appName
-                    titleView.text = title
-                    titleView.requestFocus()
-                }
+            registerOnPageChangeCallback(
+                object : ViewPager2.OnPageChangeCallback() {
+                    override fun onPageSelected(position: Int) {
+                        super.onPageSelected(position)
+                        val name = listOfStructures[position].structureName
+                        val title = if (!TextUtils.isEmpty(name)) name else appName
+                        titleView.text = title
+                        titleView.requestFocus()
+                    }
 
-                override fun onPageScrolled(
-                    position: Int,
-                    positionOffset: Float,
-                    positionOffsetPixels: Int
-                ) {
-                    super.onPageScrolled(position, positionOffset, positionOffsetPixels)
-                    pageIndicator.setLocation(position + positionOffset)
+                    override fun onPageScrolled(
+                        position: Int,
+                        positionOffset: Float,
+                        positionOffsetPixels: Int,
+                    ) {
+                        super.onPageScrolled(position, positionOffset, positionOffsetPixels)
+                        pageIndicator.setLocation(position + positionOffset)
+                    }
                 }
-            })
+            )
         }
     }
 
     private fun bindViews() {
         setContentView(R.layout.controls_management)
 
+        applyInsets(R.id.controls_management_root)
+
         lifecycle.addObserver(
             ControlsAnimations.observerForAnimations(
                 requireViewById<ViewGroup>(R.id.controls_management_root),
                 window,
-                intent
+                intent,
             )
         )
 
@@ -260,41 +305,43 @@
 
         statusText = requireViewById(R.id.status_message)
         if (shouldShowTooltip()) {
-            mTooltipManager = TooltipManager(statusText.context,
-                TOOLTIP_PREFS_KEY, TOOLTIP_MAX_SHOWN)
+            mTooltipManager =
+                TooltipManager(statusText.context, TOOLTIP_PREFS_KEY, TOOLTIP_MAX_SHOWN)
             addContentView(
                 mTooltipManager?.layout,
                 FrameLayout.LayoutParams(
                     ViewGroup.LayoutParams.WRAP_CONTENT,
                     ViewGroup.LayoutParams.WRAP_CONTENT,
-                    Gravity.TOP or Gravity.LEFT
-                )
+                    Gravity.TOP or Gravity.LEFT,
+                ),
             )
         }
-        pageIndicator = requireViewById<ManagementPageIndicator>(
-            R.id.structure_page_indicator).apply {
-            visibilityListener = {
-                if (it != View.VISIBLE) {
+        pageIndicator =
+            requireViewById<ManagementPageIndicator>(R.id.structure_page_indicator).apply {
+                visibilityListener = {
+                    if (it != View.VISIBLE) {
+                        mTooltipManager?.hide(true)
+                    }
+                }
+            }
+
+        val title =
+            structureExtra
+                ?: (appName ?: resources.getText(R.string.controls_favorite_default_title))
+        titleView = requireViewById<TextView>(R.id.title).apply { text = title }
+        subtitleView =
+            requireViewById<TextView>(R.id.subtitle).apply {
+                text = resources.getText(R.string.controls_favorite_subtitle)
+            }
+        structurePager = requireViewById<ViewPager2>(R.id.structure_pager)
+        structurePager.registerOnPageChangeCallback(
+            object : ViewPager2.OnPageChangeCallback() {
+                override fun onPageSelected(position: Int) {
+                    super.onPageSelected(position)
                     mTooltipManager?.hide(true)
                 }
             }
-        }
-
-        val title = structureExtra
-            ?: (appName ?: resources.getText(R.string.controls_favorite_default_title))
-        titleView = requireViewById<TextView>(R.id.title).apply {
-            text = title
-        }
-        subtitleView = requireViewById<TextView>(R.id.subtitle).apply {
-            text = resources.getText(R.string.controls_favorite_subtitle)
-        }
-        structurePager = requireViewById<ViewPager2>(R.id.structure_pager)
-        structurePager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
-            override fun onPageSelected(position: Int) {
-                super.onPageSelected(position)
-                mTooltipManager?.hide(true)
-            }
-        })
+        )
         bindButtons()
     }
 
@@ -307,47 +354,53 @@
                     override fun run() {
                         finish()
                     }
-                }
-        ).start()
+                },
+            )
+            .start()
     }
 
     private fun bindButtons() {
-        rearrangeButton = requireViewById<Button>(R.id.rearrange).apply {
-            text = if (fromEditing) {
-                getString(R.string.controls_favorite_back_to_editing)
-            } else {
-                getString(R.string.controls_favorite_rearrange_button)
+        rearrangeButton =
+            requireViewById<Button>(R.id.rearrange).apply {
+                text =
+                    if (fromEditing) {
+                        getString(R.string.controls_favorite_back_to_editing)
+                    } else {
+                        getString(R.string.controls_favorite_rearrange_button)
+                    }
+                isEnabled = false
+                visibility = View.VISIBLE
+                setOnClickListener {
+                    if (component == null) return@setOnClickListener
+                    saveFavorites()
+                    startActivity(
+                        Intent(context, ControlsEditingActivity::class.java).also {
+                            it.putExtra(Intent.EXTRA_COMPONENT_NAME, component)
+                            it.putExtra(ControlsEditingActivity.EXTRA_APP, appName)
+                            it.putExtra(ControlsEditingActivity.EXTRA_FROM_FAVORITING, true)
+                            it.putExtra(
+                                ControlsEditingActivity.EXTRA_STRUCTURE,
+                                listOfStructures[structurePager.currentItem].structureName,
+                            )
+                        },
+                        ActivityOptions.makeSceneTransitionAnimation(
+                                this@ControlsFavoritingActivity
+                            )
+                            .toBundle(),
+                    )
+                }
             }
-            isEnabled = false
-            visibility = View.VISIBLE
-            setOnClickListener {
-                if (component == null) return@setOnClickListener
-                saveFavorites()
-                startActivity(
-                    Intent(context, ControlsEditingActivity::class.java).also {
-                        it.putExtra(Intent.EXTRA_COMPONENT_NAME, component)
-                        it.putExtra(ControlsEditingActivity.EXTRA_APP, appName)
-                        it.putExtra(ControlsEditingActivity.EXTRA_FROM_FAVORITING, true)
-                        it.putExtra(
-                            ControlsEditingActivity.EXTRA_STRUCTURE,
-                            listOfStructures[structurePager.currentItem].structureName,
-                        )
-                    },
-                    ActivityOptions
-                        .makeSceneTransitionAnimation(this@ControlsFavoritingActivity).toBundle()
-                )
-            }
-        }
 
-        doneButton = requireViewById<Button>(R.id.done).apply {
-            isEnabled = false
-            setOnClickListener {
-                if (component == null) return@setOnClickListener
-                saveFavorites()
-                animateExitAndFinish()
-                openControlsOrigin()
+        doneButton =
+            requireViewById<Button>(R.id.done).apply {
+                isEnabled = false
+                setOnClickListener {
+                    if (component == null) return@setOnClickListener
+                    saveFavorites()
+                    animateExitAndFinish()
+                    openControlsOrigin()
+                }
             }
-        }
     }
 
     private fun saveFavorites() {
@@ -362,14 +415,14 @@
     private fun openControlsOrigin() {
         startActivity(
             Intent(applicationContext, ControlsActivity::class.java),
-            ActivityOptions.makeSceneTransitionAnimation(this).toBundle()
+            ActivityOptions.makeSceneTransitionAnimation(this).toBundle(),
         )
     }
 
     override fun onPause() {
         super.onPause()
         mTooltipManager?.hide(false)
-   }
+    }
 
     override fun onStart() {
         super.onStart()
@@ -380,7 +433,9 @@
             Log.d(TAG, "Registered onBackInvokedCallback")
         }
         onBackInvokedDispatcher.registerOnBackInvokedCallback(
-                OnBackInvokedDispatcher.PRIORITY_DEFAULT, mOnBackInvokedCallback)
+            OnBackInvokedDispatcher.PRIORITY_DEFAULT,
+            mOnBackInvokedCallback,
+        )
     }
 
     override fun onResume() {
@@ -393,7 +448,7 @@
             loadControls()
             isPagerLoaded = true
         }
-   }
+    }
 
     override fun onStop() {
         super.onStop()
@@ -403,8 +458,7 @@
         if (DEBUG) {
             Log.d(TAG, "Unregistered onBackInvokedCallback")
         }
-        onBackInvokedDispatcher.unregisterOnBackInvokedCallback(
-                mOnBackInvokedCallback)
+        onBackInvokedDispatcher.unregisterOnBackInvokedCallback(mOnBackInvokedCallback)
     }
 
     override fun onConfigurationChanged(newConfig: Configuration) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsManagementActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsManagementActivity.kt
new file mode 100644
index 0000000..c3b8cff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsManagementActivity.kt
@@ -0,0 +1,40 @@
+/*
+ * 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.controls.management
+
+import android.app.Activity
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowInsets
+import android.view.WindowInsets.Type
+
+interface ControlsManagementActivity {
+    val activity: Activity
+}
+
+fun ControlsManagementActivity.applyInsets(viewId: Int) {
+    activity.requireViewById<ViewGroup>(viewId).apply {
+        setOnApplyWindowInsetsListener { v: View, insets: WindowInsets ->
+            v.apply {
+                val paddings = insets.getInsets(Type.systemBars() or Type.displayCutout())
+                setPadding(paddings.left, paddings.top, paddings.right, paddings.bottom)
+            }
+
+            WindowInsets.CONSUMED
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
index 10a0117..f56cd00 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.controls.management
 
+import android.app.Activity
 import android.app.ActivityOptions
 import android.app.Dialog
 import android.content.ComponentName
@@ -35,7 +36,6 @@
 import androidx.annotation.VisibleForTesting
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
-import com.android.systemui.res.R
 import com.android.systemui.controls.ControlsServiceInfo
 import com.android.systemui.controls.controller.ControlsController
 import com.android.systemui.controls.panels.AuthorizedPanelsRepository
@@ -43,40 +43,46 @@
 import com.android.systemui.controls.ui.SelectedItem
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
 import java.util.concurrent.Executor
 import javax.inject.Inject
 
-/**
- * Activity to select an application to favorite the [Control] provided by them.
- */
-open class ControlsProviderSelectorActivity @Inject constructor(
+/** Activity to select an application to favorite the [Control] provided by them. */
+open class ControlsProviderSelectorActivity
+@Inject
+constructor(
     @Main private val executor: Executor,
     @Background private val backExecutor: Executor,
     private val listingController: ControlsListingController,
     private val controlsController: ControlsController,
     private val userTracker: UserTracker,
     private val authorizedPanelsRepository: AuthorizedPanelsRepository,
-    private val panelConfirmationDialogFactory: PanelConfirmationDialogFactory
-) : ComponentActivity() {
+    private val panelConfirmationDialogFactory: PanelConfirmationDialogFactory,
+) : ComponentActivity(), ControlsManagementActivity {
 
     companion object {
         private const val DEBUG = false
         private const val TAG = "ControlsProviderSelectorActivity"
         const val BACK_SHOULD_EXIT = "back_should_exit"
     }
+
+    override val activity: Activity
+        get() = this
+
     private var backShouldExit = false
     private lateinit var recyclerView: RecyclerView
-    private val userTrackerCallback: UserTracker.Callback = object : UserTracker.Callback {
-        private val startingUser = listingController.currentUserId
+    private val userTrackerCallback: UserTracker.Callback =
+        object : UserTracker.Callback {
+            private val startingUser = listingController.currentUserId
 
-        override fun onUserChanged(newUser: Int, userContext: Context) {
-            if (newUser != startingUser) {
-                userTracker.removeCallback(this)
-                finish()
+            override fun onUserChanged(newUser: Int, userContext: Context) {
+                if (newUser != startingUser) {
+                    userTracker.removeCallback(this)
+                    finish()
+                }
             }
         }
-    }
     private var dialog: Dialog? = null
 
     private val mOnBackInvokedCallback = OnBackInvokedCallback {
@@ -95,10 +101,12 @@
             ControlsAnimations.observerForAnimations(
                 requireViewById<ViewGroup>(R.id.controls_management_root),
                 window,
-                intent
+                intent,
             )
         )
 
+        applyInsets(R.id.controls_management_root)
+
         requireViewById<ViewStub>(R.id.stub).apply {
             layoutResource = R.layout.controls_management_apps
             inflate()
@@ -114,9 +122,7 @@
         requireViewById<Button>(R.id.other_apps).apply {
             visibility = View.VISIBLE
             setText(com.android.internal.R.string.cancel)
-            setOnClickListener {
-                onBackPressed()
-            }
+            setOnClickListener { onBackPressed() }
         }
         requireViewById<View>(R.id.done).visibility = View.GONE
 
@@ -125,9 +131,10 @@
 
     override fun onBackPressed() {
         if (!backShouldExit) {
-            val i = Intent().apply {
-                component = ComponentName(applicationContext, ControlsActivity::class.java)
-            }
+            val i =
+                Intent().apply {
+                    component = ComponentName(applicationContext, ControlsActivity::class.java)
+                }
             startActivity(i, ActivityOptions.makeSceneTransitionAnimation(this).toBundle())
         }
         animateExitAndFinish()
@@ -138,33 +145,40 @@
         userTracker.addCallback(userTrackerCallback, executor)
 
         recyclerView.alpha = 0.0f
-        recyclerView.adapter = AppAdapter(
-                backExecutor,
-                executor,
-                lifecycle,
-                listingController,
-                LayoutInflater.from(this),
-                ::onAppSelected,
-                FavoritesRenderer(resources, controlsController::countFavoritesForComponent),
-                resources,
-                authorizedPanelsRepository.getAuthorizedPanels()
-        ).apply {
-            registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
-                var hasAnimated = false
-                override fun onChanged() {
-                    if (!hasAnimated) {
-                        hasAnimated = true
-                        ControlsAnimations.enterAnimation(recyclerView).start()
-                    }
+        recyclerView.adapter =
+            AppAdapter(
+                    backExecutor,
+                    executor,
+                    lifecycle,
+                    listingController,
+                    LayoutInflater.from(this),
+                    ::onAppSelected,
+                    FavoritesRenderer(resources, controlsController::countFavoritesForComponent),
+                    resources,
+                    authorizedPanelsRepository.getAuthorizedPanels(),
+                )
+                .apply {
+                    registerAdapterDataObserver(
+                        object : RecyclerView.AdapterDataObserver() {
+                            var hasAnimated = false
+
+                            override fun onChanged() {
+                                if (!hasAnimated) {
+                                    hasAnimated = true
+                                    ControlsAnimations.enterAnimation(recyclerView).start()
+                                }
+                            }
+                        }
+                    )
                 }
-            })
-        }
 
         if (DEBUG) {
             Log.d(TAG, "Registered onBackInvokedCallback")
         }
         onBackInvokedDispatcher.registerOnBackInvokedCallback(
-                OnBackInvokedDispatcher.PRIORITY_DEFAULT, mOnBackInvokedCallback)
+            OnBackInvokedDispatcher.PRIORITY_DEFAULT,
+            mOnBackInvokedCallback,
+        )
     }
 
     override fun onStop() {
@@ -184,38 +198,45 @@
             launchFavoritingActivity(serviceInfo.componentName)
         } else {
             val appName = serviceInfo.loadLabel() ?: ""
-            dialog = panelConfirmationDialogFactory.createConfirmationDialog(this, appName) { ok ->
-                if (ok) {
-                    authorizedPanelsRepository.addAuthorizedPanels(
-                            setOf(serviceInfo.componentName.packageName)
-                    )
-                    val selected = SelectedItem.PanelItem(appName, serviceInfo.componentName)
-                    controlsController.setPreferredSelection(selected)
-                    animateExitAndFinish()
-                    openControlsOrigin()
-                }
-                dialog = null
-            }.also { it.show() }
+            dialog =
+                panelConfirmationDialogFactory
+                    .createConfirmationDialog(this, appName) { ok ->
+                        if (ok) {
+                            authorizedPanelsRepository.addAuthorizedPanels(
+                                setOf(serviceInfo.componentName.packageName)
+                            )
+                            val selected =
+                                SelectedItem.PanelItem(appName, serviceInfo.componentName)
+                            controlsController.setPreferredSelection(selected)
+                            animateExitAndFinish()
+                            openControlsOrigin()
+                        }
+                        dialog = null
+                    }
+                    .also { it.show() }
         }
     }
 
     /**
      * Launch the [ControlsFavoritingActivity] for the specified component.
+     *
      * @param component a component name for a [ControlsProviderService]
      */
     private fun launchFavoritingActivity(component: ComponentName?) {
         executor.execute {
             component?.let {
-                val intent = Intent(applicationContext, ControlsFavoritingActivity::class.java)
-                        .apply {
-                    putExtra(ControlsFavoritingActivity.EXTRA_APP,
-                            listingController.getAppLabel(it))
-                    putExtra(Intent.EXTRA_COMPONENT_NAME, it)
-                    putExtra(
-                        ControlsFavoritingActivity.EXTRA_SOURCE,
-                        ControlsFavoritingActivity.EXTRA_SOURCE_VALUE_FROM_PROVIDER_SELECTOR,
-                    )
-                }
+                val intent =
+                    Intent(applicationContext, ControlsFavoritingActivity::class.java).apply {
+                        putExtra(
+                            ControlsFavoritingActivity.EXTRA_APP,
+                            listingController.getAppLabel(it),
+                        )
+                        putExtra(Intent.EXTRA_COMPONENT_NAME, it)
+                        putExtra(
+                            ControlsFavoritingActivity.EXTRA_SOURCE,
+                            ControlsFavoritingActivity.EXTRA_SOURCE_VALUE_FROM_PROVIDER_SELECTOR,
+                        )
+                    }
                 startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle())
             }
         }
@@ -228,8 +249,8 @@
 
     private fun openControlsOrigin() {
         startActivity(
-                Intent(applicationContext, ControlsActivity::class.java),
-                ActivityOptions.makeSceneTransitionAnimation(this).toBundle()
+            Intent(applicationContext, ControlsActivity::class.java),
+            ActivityOptions.makeSceneTransitionAnimation(this).toBundle(),
         )
     }
 
@@ -242,7 +263,8 @@
                     override fun run() {
                         finish()
                     }
-                }
-        ).start()
+                },
+            )
+            .start()
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
index 955a5a3..8296ec2 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.controls.ui
 
+import android.app.Activity
 import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
@@ -25,36 +26,40 @@
 import android.os.Bundle
 import android.os.RemoteException
 import android.service.dreams.IDreamManager
-import android.view.View
 import android.view.ViewGroup
-import android.view.WindowInsets
-import android.view.WindowInsets.Type
 import android.view.WindowManager
 import androidx.activity.ComponentActivity
-import com.android.systemui.res.R
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.controls.management.ControlsAnimations
+import com.android.systemui.controls.management.ControlsManagementActivity
+import com.android.systemui.controls.management.applyInsets
 import com.android.systemui.controls.settings.ControlsSettingsDialogManager
 import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.res.R
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import javax.inject.Inject
 
 /**
  * Displays Device Controls inside an activity. This activity is available to be displayed over the
  * lockscreen if the user has allowed it via
- * [android.provider.Settings.Secure.LOCKSCREEN_SHOW_CONTROLS]. This activity will be
- * destroyed on SCREEN_OFF events, due to issues with occluded activities over lockscreen as well as
- * user expectations for the activity to not continue running.
+ * [android.provider.Settings.Secure.LOCKSCREEN_SHOW_CONTROLS]. This activity will be destroyed on
+ * SCREEN_OFF events, due to issues with occluded activities over lockscreen as well as user
+ * expectations for the activity to not continue running.
  */
 // Open for testing
-open class ControlsActivity @Inject constructor(
+open class ControlsActivity
+@Inject
+constructor(
     private val uiController: ControlsUiController,
     private val broadcastDispatcher: BroadcastDispatcher,
     private val dreamManager: IDreamManager,
     private val featureFlags: FeatureFlags,
     private val controlsSettingsDialogManager: ControlsSettingsDialogManager,
-    private val keyguardStateController: KeyguardStateController
-) : ComponentActivity() {
+    private val keyguardStateController: KeyguardStateController,
+) : ComponentActivity(), ControlsManagementActivity {
+
+    override val activity: Activity
+        get() = this
 
     private val lastConfiguration = Configuration()
 
@@ -69,38 +74,27 @@
 
         setContentView(R.layout.controls_fullscreen)
 
+        applyInsets(R.id.control_detail_root)
+
         lifecycle.addObserver(
             ControlsAnimations.observerForAnimations(
                 requireViewById(R.id.control_detail_root),
                 window,
                 intent,
-                false
+                false,
             )
         )
 
-        requireViewById<ViewGroup>(R.id.control_detail_root).apply {
-            setOnApplyWindowInsetsListener {
-                v: View, insets: WindowInsets ->
-                    v.apply {
-                        val l = getPaddingLeft()
-                        val t = getPaddingTop()
-                        val r = getPaddingRight()
-                        setPadding(l, t, r, insets.getInsets(Type.systemBars()).bottom)
-                    }
-
-                WindowInsets.CONSUMED
-            }
-        }
-
         initBroadcastReceiver()
     }
 
     override fun onConfigurationChanged(newConfig: Configuration) {
         super.onConfigurationChanged(newConfig)
-        val interestingFlags = ActivityInfo.CONFIG_ORIENTATION or
+        val interestingFlags =
+            ActivityInfo.CONFIG_ORIENTATION or
                 ActivityInfo.CONFIG_SCREEN_SIZE or
                 ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE
-        if (lastConfiguration.diff(newConfig) and interestingFlags != 0 ) {
+        if (lastConfiguration.diff(newConfig) and interestingFlags != 0) {
             uiController.onSizeChange()
         }
         lastConfiguration.setTo(newConfig)
@@ -164,15 +158,18 @@
     }
 
     private fun initBroadcastReceiver() {
-        broadcastReceiver = object : BroadcastReceiver() {
-            override fun onReceive(context: Context, intent: Intent) {
-                val action = intent.getAction()
-                if (action == Intent.ACTION_SCREEN_OFF ||
-                    action == Intent.ACTION_DREAMING_STARTED) {
-                    finish()
+        broadcastReceiver =
+            object : BroadcastReceiver() {
+                override fun onReceive(context: Context, intent: Intent) {
+                    val action = intent.getAction()
+                    if (
+                        action == Intent.ACTION_SCREEN_OFF ||
+                            action == Intent.ACTION_DREAMING_STARTED
+                    ) {
+                        finish()
+                    }
                 }
             }
-        }
 
         val filter = IntentFilter()
         filter.addAction(Intent.ACTION_SCREEN_OFF)
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 2e323d4..1fc5494 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -75,7 +75,7 @@
 import com.android.systemui.statusbar.notification.dagger.ReferenceNotificationsModule;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.DozeServiceHost;
-import com.android.systemui.statusbar.phone.HeadsUpModule;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpModule;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule;
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentStartableModule;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 7b91eae..fcc3ea9 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -25,6 +25,8 @@
 import com.android.systemui.biometrics.BiometricNotificationService
 import com.android.systemui.bouncer.domain.startable.BouncerStartable
 import com.android.systemui.clipboardoverlay.ClipboardListener
+import com.android.systemui.complication.ComplicationTypesUpdater
+import com.android.systemui.complication.DreamClockTimeComplication
 import com.android.systemui.controls.dagger.StartControlsStartableModule
 import com.android.systemui.dagger.qualifiers.PerUser
 import com.android.systemui.dreams.AssistantAttentionMonitor
@@ -52,7 +54,7 @@
 import com.android.systemui.statusbar.ImmersiveModeConfirmation
 import com.android.systemui.statusbar.gesture.GesturePointerEventListener
 import com.android.systemui.statusbar.notification.InstantAppNotifier
-import com.android.systemui.statusbar.phone.StatusBarHeadsUpChangeListener
+import com.android.systemui.statusbar.notification.headsup.StatusBarHeadsUpChangeListener
 import com.android.systemui.statusbar.policy.BatteryControllerStartable
 import com.android.systemui.stylus.StylusUsiPowerStartable
 import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
@@ -337,4 +339,18 @@
     abstract fun bindDreamOverlayRegistrant(
         dreamOverlayRegistrant: DreamOverlayRegistrant
     ): CoreStartable
+
+    /** Inject into DreamClockTimeComplication.Registrant */
+    @Binds
+    @IntoMap
+    @ClassKey(DreamClockTimeComplication.Registrant::class)
+    abstract fun bindDreamClockTimeComplicationRegistrant(
+        registrant: DreamClockTimeComplication.Registrant
+    ): CoreStartable
+
+    /** Inject into ComplicationTypesUpdater. */
+    @Binds
+    @IntoMap
+    @ClassKey(ComplicationTypesUpdater::class)
+    abstract fun bindComplicationTypesUpdater(updater: ComplicationTypesUpdater): CoreStartable
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index b7d3c92..d6f8957 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -32,6 +32,7 @@
 import com.android.systemui.CameraProtectionModule;
 import com.android.systemui.CoreStartable;
 import com.android.systemui.SystemUISecondaryUserService;
+import com.android.systemui.activity.ActivityManagerModule;
 import com.android.systemui.ambient.dagger.AmbientModule;
 import com.android.systemui.appops.dagger.AppOpsModule;
 import com.android.systemui.assist.AssistModule;
@@ -140,7 +141,7 @@
 import com.android.systemui.statusbar.phone.ConfigurationControllerModule;
 import com.android.systemui.statusbar.phone.LetterboxModule;
 import com.android.systemui.statusbar.pipeline.dagger.StatusBarPipelineModule;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.PolicyModule;
 import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController;
@@ -198,6 +199,7 @@
  * may not appreciate that.
  */
 @Module(includes = {
+        ActivityManagerModule.class,
         AmbientModule.class,
         AppOpsModule.class,
         AssistModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
index 400d097..2e1096f 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
@@ -84,30 +84,53 @@
             )
 
     /**
+     * Emits `true` when the current scene switches to [Scenes.Gone] for the first time after having
+     * been on [Scenes.Lockscreen].
+     *
+     * Different from [isDeviceEntered] such that the current scene must actually go through
+     * [Scenes.Gone] to produce a `true`. [isDeviceEntered] also takes into account the navigation
+     * back stack and will produce a `true` value even when the current scene is still not
+     * [Scenes.Gone] but the bottommost entry of the navigation back stack switched from
+     * [Scenes.Lockscreen] to [Scenes.Gone] while the user is staring at another scene.
+     */
+    val isDeviceEnteredDirectly: StateFlow<Boolean> =
+        sceneInteractor.currentScene
+            .filter { currentScene ->
+                currentScene == Scenes.Gone || currentScene == Scenes.Lockscreen
+            }
+            .mapLatestConflated { scene ->
+                if (scene == Scenes.Gone) {
+                    // Make sure device unlock status is definitely unlocked before we
+                    // consider the device "entered".
+                    deviceUnlockedInteractor.deviceUnlockStatus.first { it.isUnlocked }
+                    true
+                } else {
+                    false
+                }
+            }
+            .stateIn(
+                scope = applicationScope,
+                started = SharingStarted.Eagerly,
+                initialValue = false,
+            )
+
+    /**
      * Whether the device has been entered (i.e. the lockscreen has been dismissed, by any method).
      * This can be `false` when the device is unlocked, e.g. when the user still needs to swipe away
      * the non-secure lockscreen, even though they've already authenticated.
      *
      * Note: This does not imply that the lockscreen is visible or not.
+     *
+     * Different from [isDeviceEnteredDirectly] such that the current scene doesn't actually have to
+     * go through [Scenes.Gone] to produce a `true`. [isDeviceEnteredDirectly] doesn't take the
+     * navigation back stack into account and will only produce a `true` value even when the current
+     * scene is actually [Scenes.Gone].
      */
     val isDeviceEntered: StateFlow<Boolean> =
         combine(
                 // This flow emits true when the currentScene switches to Gone for the first time
                 // after having been on Lockscreen.
-                sceneInteractor.currentScene
-                    .filter { currentScene ->
-                        currentScene == Scenes.Gone || currentScene == Scenes.Lockscreen
-                    }
-                    .mapLatestConflated { scene ->
-                        if (scene == Scenes.Gone) {
-                            // Make sure device unlock status is definitely unlocked before we
-                            // consider the device "entered".
-                            deviceUnlockedInteractor.deviceUnlockStatus.first { it.isUnlocked }
-                            true
-                        } else {
-                            false
-                        }
-                    },
+                isDeviceEnteredDirectly,
                 // This flow emits true only if the bottom of the navigation back stack has been
                 // switched from Lockscreen to Gone. In other words, only if the device was unlocked
                 // while visiting at least one scene "above" the Lockscreen scene.
diff --git a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
index e862525..9b181be 100644
--- a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
@@ -30,6 +30,7 @@
 import com.android.systemui.display.data.repository.FocusedDisplayRepositoryImpl
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractorImpl
+import com.android.systemui.display.domain.interactor.DisplayWindowPropertiesInteractorModule
 import com.android.systemui.display.domain.interactor.RearDisplayStateInteractor
 import com.android.systemui.display.domain.interactor.RearDisplayStateInteractorImpl
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
@@ -41,7 +42,7 @@
 import dagger.multibindings.IntoMap
 
 /** Module binding display related classes. */
-@Module
+@Module(includes = [DisplayWindowPropertiesInteractorModule::class])
 interface DisplayModule {
     @Binds
     fun bindConnectedDisplayInteractor(
diff --git a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/DisplayWindowPropertiesInteractor.kt b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/DisplayWindowPropertiesInteractor.kt
new file mode 100644
index 0000000..22e467b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/DisplayWindowPropertiesInteractor.kt
@@ -0,0 +1,55 @@
+/*
+ * 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.display.domain.interactor
+
+import android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
+import com.android.systemui.display.shared.model.DisplayWindowProperties
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
+
+/** Provides per display instances of [DisplayWindowProperties]. */
+interface DisplayWindowPropertiesInteractor {
+
+    /**
+     * Returns a [DisplayWindowProperties] instance for a given display id, to be used for the
+     * status bar.
+     *
+     * @throws IllegalArgumentException if no display with the given display id exists.
+     */
+    fun getForStatusBar(displayId: Int): DisplayWindowProperties
+}
+
+@SysUISingleton
+class DisplayWindowPropertiesInteractorImpl
+@Inject
+constructor(private val repo: DisplayWindowPropertiesRepository) :
+    DisplayWindowPropertiesInteractor {
+
+    override fun getForStatusBar(displayId: Int): DisplayWindowProperties {
+        return repo.get(displayId, TYPE_STATUS_BAR)
+    }
+}
+
+@Module
+interface DisplayWindowPropertiesInteractorModule {
+
+    @Binds
+    fun interactor(impl: DisplayWindowPropertiesInteractorImpl): DisplayWindowPropertiesInteractor
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 408fe83..43b7ced 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -18,6 +18,7 @@
 
 import static android.service.dreams.Flags.dreamWakeRedirect;
 
+import static com.android.systemui.Flags.communalHubOnMobile;
 import static com.android.systemui.Flags.glanceableHubAllowKeyguardWhenDreaming;
 import static com.android.systemui.dreams.dagger.DreamModule.DREAM_OVERLAY_WINDOW_TITLE;
 import static com.android.systemui.dreams.dagger.DreamModule.DREAM_TOUCH_INSET_MANAGER;
@@ -54,12 +55,14 @@
 import com.android.internal.policy.PhoneWindow;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.ambient.touch.TouchHandler;
 import com.android.systemui.ambient.touch.TouchMonitor;
 import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent;
 import com.android.systemui.ambient.touch.scrim.ScrimManager;
 import com.android.systemui.communal.domain.interactor.CommunalInteractor;
 import com.android.systemui.communal.shared.log.CommunalUiEvent;
 import com.android.systemui.communal.shared.model.CommunalScenes;
+import com.android.systemui.communal.shared.model.CommunalTransitionKeys;
 import com.android.systemui.complication.dagger.ComplicationComponent;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dreams.dagger.DreamOverlayComponent;
@@ -76,8 +79,8 @@
 import kotlinx.coroutines.Job;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashSet;
+import java.util.List;
 import java.util.concurrent.CancellationException;
 import java.util.function.Consumer;
 
@@ -483,11 +486,16 @@
         final DreamOverlayComponent dreamOverlayComponent = mDreamOverlayComponentFactory.create(
                 mLifecycleOwner, complicationComponent.getComplicationHostViewController(),
                 mTouchInsetManager);
+
+        final ArrayList<TouchHandler> touchHandlers = new ArrayList<>(
+                List.of(dreamComplicationComponent.getHideComplicationTouchHandler()));
+        if (!communalHubOnMobile()) {
+            // Do not add the communal touch handler for glanceable hub v2 since there is no dream
+            // to hub swipe gesture.
+            touchHandlers.add(dreamOverlayComponent.getCommunalTouchHandler());
+        }
         final AmbientTouchComponent ambientTouchComponent = mAmbientTouchComponentFactory.create(
-                mLifecycleOwner,
-                new HashSet<>(Arrays.asList(
-                        dreamComplicationComponent.getHideComplicationTouchHandler(),
-                        dreamOverlayComponent.getCommunalTouchHandler())), TAG);
+                mLifecycleOwner, new HashSet<>(touchHandlers), TAG);
 
         setLifecycleStateLocked(Lifecycle.State.STARTED);
 
@@ -568,7 +576,7 @@
         } else {
             mCommunalInteractor.changeScene(CommunalScenes.Communal,
                     "dream wake requested",
-                    null);
+                    communalHubOnMobile() ? CommunalTransitionKeys.INSTANCE.getSimpleFade() : null);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModel.kt
index b37206a..160574fa 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModel.kt
@@ -19,6 +19,7 @@
 import com.android.compose.animation.scene.Swipe
 import com.android.compose.animation.scene.UserAction
 import com.android.compose.animation.scene.UserActionResult
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.ui.viewmodel.UserActionsViewModel
@@ -38,6 +39,7 @@
 class DreamUserActionsViewModel
 @AssistedInject
 constructor(
+    private val communalInteractor: CommunalInteractor,
     private val deviceUnlockedInteractor: DeviceUnlockedInteractor,
     private val shadeInteractor: ShadeInteractor,
 ) : UserActionsViewModel() {
@@ -50,10 +52,13 @@
                 } else {
                     combine(
                         deviceUnlockedInteractor.deviceUnlockStatus.map { it.isUnlocked },
+                        communalInteractor.isCommunalAvailable,
                         shadeInteractor.shadeMode,
-                    ) { isDeviceUnlocked, shadeMode ->
+                    ) { isDeviceUnlocked, isCommunalAvailable, shadeMode ->
                         buildList {
-                                add(Swipe.Start to Scenes.Communal)
+                                if (isCommunalAvailable) {
+                                    add(Swipe.Start to Scenes.Communal)
+                                }
 
                                 val bouncerOrGone =
                                     if (isDeviceUnlocked) Scenes.Gone else Scenes.Bouncer
diff --git a/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduUiCoordinator.kt b/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduUiCoordinator.kt
index 2a3729b..c49ba80 100644
--- a/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduUiCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduUiCoordinator.kt
@@ -27,6 +27,7 @@
 import android.os.UserHandle
 import android.view.accessibility.AccessibilityManager
 import androidx.core.app.NotificationCompat
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
@@ -39,7 +40,6 @@
 import com.android.systemui.res.R
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 /**
  * A class to show contextual education on UI based on the edu produced from
@@ -107,6 +107,7 @@
     }
 
     private fun showDialog(model: ContextualEduToastViewModel) {
+        dialog?.dismiss()
         dialog = createDialog(model)
         dialog?.show()
     }
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartable.kt
index 092a25a..7bd09b9 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartable.kt
@@ -20,6 +20,7 @@
 import android.content.Context
 import android.content.Intent
 import android.content.IntentFilter
+import android.os.Build
 import android.os.UserHandle
 import com.android.systemui.CoreStartable
 import com.android.systemui.broadcast.BroadcastDispatcher
@@ -52,13 +53,13 @@
             receiver =
                 object : BroadcastReceiver() {
                     override fun onReceive(context: Context, intent: Intent) {
-                        applicationContext.startActivityAsUser(
-                            Intent(
-                                applicationContext,
-                                KeyboardTouchpadTutorialActivity::class.java
-                            ),
-                            UserHandle.SYSTEM
-                        )
+                        val activityIntent =
+                            Intent(applicationContext, KeyboardTouchpadTutorialActivity::class.java)
+                        if (Build.IS_DEBUGGABLE) {
+                            // helpful for testing different cases but pointless for public builds
+                            intent.extras?.let { activityIntent.putExtras(it) }
+                        }
+                        applicationContext.startActivityAsUser(activityIntent, UserHandle.SYSTEM)
                     }
                 },
             filter = IntentFilter("com.android.systemui.action.KEYBOARD_TOUCHPAD_TUTORIAL"),
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialMetricsLogger.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialMetricsLogger.kt
index 144c5ead..ae6cbbc 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialMetricsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialMetricsLogger.kt
@@ -18,8 +18,8 @@
 
 import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_ENTRY_POINT_CONTEXTUAL_EDU
 import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_ENTRY_POINT_SCHEDULER
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_KEYBOARD
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_TOUCHPAD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_KEYBOARD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_TOUCHPAD
 import com.android.systemui.shared.system.SysUiStatsLog
 import javax.inject.Inject
 
@@ -37,9 +37,9 @@
 
         val tutorialType =
             when (tutorialTypeExtra) {
-                INTENT_TUTORIAL_TYPE_KEYBOARD ->
+                INTENT_TUTORIAL_SCOPE_KEYBOARD ->
                     SysUiStatsLog.PERIPHERAL_TUTORIAL_LAUNCHED__TUTORIAL_TYPE__KEYBOARD
-                INTENT_TUTORIAL_TYPE_TOUCHPAD ->
+                INTENT_TUTORIAL_SCOPE_TOUCHPAD ->
                     SysUiStatsLog.PERIPHERAL_TUTORIAL_LAUNCHED__TUTORIAL_TYPE__TOUCHPAD
                 else -> SysUiStatsLog.PERIPHERAL_TUTORIAL_LAUNCHED__TUTORIAL_TYPE__BOTH
             }
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/TutorialNotificationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/TutorialNotificationCoordinator.kt
index 9dae649..3cba70e 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/TutorialNotificationCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/TutorialNotificationCoordinator.kt
@@ -34,10 +34,10 @@
 import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity
 import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_ENTRY_POINT_KEY
 import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_ENTRY_POINT_SCHEDULER
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_BOTH
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_KEY
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_KEYBOARD
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_TOUCHPAD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_ALL
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_KEY
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_KEYBOARD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_TOUCHPAD
 import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
 import javax.inject.Inject
@@ -108,7 +108,7 @@
     private fun createPendingIntent(tutorialType: String): PendingIntent {
         val intent =
             Intent(context, KeyboardTouchpadTutorialActivity::class.java).apply {
-                putExtra(INTENT_TUTORIAL_TYPE_KEY, tutorialType)
+                putExtra(INTENT_TUTORIAL_SCOPE_KEY, tutorialType)
                 putExtra(INTENT_TUTORIAL_ENTRY_POINT_KEY, INTENT_TUTORIAL_ENTRY_POINT_SCHEDULER)
                 flags = Intent.FLAG_ACTIVITY_NEW_TASK
             }
@@ -128,13 +128,13 @@
                 NotificationInfo(
                     context.getString(R.string.launch_keyboard_tutorial_notification_title),
                     context.getString(R.string.launch_keyboard_tutorial_notification_content),
-                    INTENT_TUTORIAL_TYPE_KEYBOARD,
+                    INTENT_TUTORIAL_SCOPE_KEYBOARD,
                 )
             TutorialType.TOUCHPAD ->
                 NotificationInfo(
                     context.getString(R.string.launch_touchpad_tutorial_notification_title),
                     context.getString(R.string.launch_touchpad_tutorial_notification_content),
-                    INTENT_TUTORIAL_TYPE_TOUCHPAD,
+                    INTENT_TUTORIAL_SCOPE_TOUCHPAD,
                 )
             TutorialType.BOTH ->
                 NotificationInfo(
@@ -144,7 +144,7 @@
                     context.getString(
                         R.string.launch_keyboard_touchpad_tutorial_notification_content
                     ),
-                    INTENT_TUTORIAL_TYPE_BOTH,
+                    INTENT_TUTORIAL_SCOPE_ALL,
                 )
             TutorialType.NONE -> null
         }
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialAnimation.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialAnimation.kt
index 2be619b..abd39cc 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialAnimation.kt
@@ -23,13 +23,16 @@
 import androidx.compose.animation.core.tween
 import androidx.compose.animation.fadeOut
 import androidx.compose.animation.togetherWith
+import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.node.Ref
@@ -93,13 +96,19 @@
     animationProperties: LottieDynamicProperties,
 ) {
     val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(educationAnimationId))
+    var isPlaying by remember { mutableStateOf(true) }
     val progress by
-        animateLottieCompositionAsState(composition, iterations = LottieConstants.IterateForever)
+        animateLottieCompositionAsState(
+            composition,
+            iterations = LottieConstants.IterateForever,
+            isPlaying = isPlaying,
+            restartOnPlay = false,
+        )
     LottieAnimation(
         composition = composition,
         progress = { progress },
         dynamicProperties = animationProperties,
-        modifier = Modifier.fillMaxSize(),
+        modifier = Modifier.fillMaxSize().clickable { isPlaying = !isPlaying },
     )
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt
index fee08b3..67b307f 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt
@@ -56,10 +56,13 @@
 ) : ComponentActivity() {
 
     companion object {
-        const val INTENT_TUTORIAL_TYPE_KEY = "tutorial_type"
-        const val INTENT_TUTORIAL_TYPE_TOUCHPAD = "touchpad"
-        const val INTENT_TUTORIAL_TYPE_KEYBOARD = "keyboard"
-        const val INTENT_TUTORIAL_TYPE_BOTH = "both"
+        const val INTENT_TUTORIAL_SCOPE_KEY = "tutorial_scope"
+        const val INTENT_TUTORIAL_SCOPE_TOUCHPAD = "touchpad"
+        const val INTENT_TUTORIAL_SCOPE_TOUCHPAD_BACK = "touchpad_back"
+        const val INTENT_TUTORIAL_SCOPE_TOUCHPAD_HOME = "touchpad_home"
+        const val INTENT_TUTORIAL_SCOPE_KEYBOARD = "keyboard"
+        const val INTENT_TUTORIAL_SCOPE_ALL = "all"
+
         const val INTENT_TUTORIAL_ENTRY_POINT_KEY = "entry_point"
         const val INTENT_TUTORIAL_ENTRY_POINT_SCHEDULER = "scheduler"
         const val INTENT_TUTORIAL_ENTRY_POINT_CONTEXTUAL_EDU = "contextual_edu"
@@ -94,7 +97,7 @@
         if (savedInstanceState == null) {
             metricsLogger.logPeripheralTutorialLaunched(
                 intent.getStringExtra(INTENT_TUTORIAL_ENTRY_POINT_KEY),
-                intent.getStringExtra(INTENT_TUTORIAL_TYPE_KEY),
+                intent.getStringExtra(INTENT_TUTORIAL_SCOPE_KEY),
             )
             logger.logOpenTutorial(TutorialContext.KEYBOARD_TOUCHPAD_TUTORIAL)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt
index 896bdc0..eeb4b69 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt
@@ -22,15 +22,21 @@
 import androidx.lifecycle.SavedStateHandle
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewModelScope
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger
 import com.android.systemui.inputdevice.tutorial.domain.interactor.ConnectionState
 import com.android.systemui.inputdevice.tutorial.domain.interactor.KeyboardTouchpadConnectionInteractor
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_KEY
-import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_TYPE_KEYBOARD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_ALL
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_KEY
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_KEYBOARD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_TOUCHPAD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_TOUCHPAD_BACK
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_TOUCHPAD_HOME
 import com.android.systemui.inputdevice.tutorial.ui.viewmodel.RequiredHardware.KEYBOARD
 import com.android.systemui.inputdevice.tutorial.ui.viewmodel.RequiredHardware.TOUCHPAD
 import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.ACTION_KEY
 import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.BACK_GESTURE
+import com.android.systemui.inputdevice.tutorial.ui.viewmodel.Screen.HOME_GESTURE
 import com.android.systemui.touchpad.tutorial.domain.interactor.TouchpadGesturesInteractor
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
@@ -42,27 +48,23 @@
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.filterNot
 import kotlinx.coroutines.flow.runningFold
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 class KeyboardTouchpadTutorialViewModel(
     private val gesturesInteractor: Optional<TouchpadGesturesInteractor>,
     private val keyboardTouchpadConnectionInteractor: KeyboardTouchpadConnectionInteractor,
     private val hasTouchpadTutorialScreens: Boolean,
     private val logger: InputDeviceTutorialLogger,
-    handle: SavedStateHandle
+    handle: SavedStateHandle,
 ) : ViewModel(), DefaultLifecycleObserver {
 
-    private fun startingScreen(handle: SavedStateHandle): Screen {
-        val tutorialType: String? = handle[INTENT_TUTORIAL_TYPE_KEY]
-        return if (tutorialType == INTENT_TUTORIAL_TYPE_KEYBOARD) ACTION_KEY else BACK_GESTURE
-    }
-
     private val _screen = MutableStateFlow(startingScreen(handle))
     val screen: Flow<Screen> = _screen.filter { it.canBeShown() }
 
     private val _closeActivity: MutableStateFlow<Boolean> = MutableStateFlow(false)
     val closeActivity: StateFlow<Boolean> = _closeActivity
 
+    private val screenSequence: ScreenSequence = chooseScreenSequence(handle)
+
     private val screensBackStack = ArrayDeque(listOf(_screen.value))
 
     private var connectionState: ConnectionState =
@@ -105,6 +107,33 @@
         }
     }
 
+    private fun startingScreen(handle: SavedStateHandle): Screen {
+        val scope: String? = handle[INTENT_TUTORIAL_SCOPE_KEY]
+        return when (scope) {
+            INTENT_TUTORIAL_SCOPE_KEYBOARD -> ACTION_KEY
+            INTENT_TUTORIAL_SCOPE_TOUCHPAD_HOME -> HOME_GESTURE
+            INTENT_TUTORIAL_SCOPE_TOUCHPAD,
+            INTENT_TUTORIAL_SCOPE_ALL,
+            INTENT_TUTORIAL_SCOPE_TOUCHPAD_BACK -> BACK_GESTURE
+            else -> {
+                logger.w("Intent didn't specify tutorial scope, starting with default")
+                BACK_GESTURE
+            }
+        }
+    }
+
+    private fun chooseScreenSequence(handle: SavedStateHandle): ScreenSequence {
+        val scope: String? = handle[INTENT_TUTORIAL_SCOPE_KEY]
+        return if (
+            scope == INTENT_TUTORIAL_SCOPE_TOUCHPAD_HOME ||
+                scope == INTENT_TUTORIAL_SCOPE_TOUCHPAD_BACK
+        ) {
+            SingleScreenOnly
+        } else {
+            AllSupportedScreens
+        }
+    }
+
     override fun onCleared() {
         // this shouldn't be needed as onTutorialInvisible should already clear device state but
         // it'd be really bad if we'd block gestures/shortcuts after leaving tutorial so just to be
@@ -121,13 +150,13 @@
     }
 
     fun onDoneButtonClicked() {
-        var nextScreen = _screen.value.next()
+        var nextScreen = screenSequence.nextScreen(_screen.value)
         while (nextScreen != null) {
             if (requiredHardwarePresent(nextScreen)) {
                 break
             }
             logger.logNextScreenMissingHardware(nextScreen)
-            nextScreen = nextScreen.next()
+            nextScreen = screenSequence.nextScreen(nextScreen)
         }
         if (nextScreen == null) {
             logger.d("Final screen reached, closing tutorial")
@@ -192,33 +221,44 @@
         override fun <T : ViewModel> create(
             key: String,
             modelClass: Class<T>,
-            handle: SavedStateHandle
+            handle: SavedStateHandle,
         ): T =
             KeyboardTouchpadTutorialViewModel(
                 gesturesInteractor,
                 keyboardTouchpadConnected,
                 hasTouchpadTutorialScreens,
                 logger,
-                handle
+                handle,
             )
                 as T
     }
+
+    private interface ScreenSequence {
+        fun nextScreen(current: Screen): Screen?
+    }
+
+    private object AllSupportedScreens : ScreenSequence {
+        override fun nextScreen(current: Screen): Screen? {
+            return when (current) {
+                BACK_GESTURE -> HOME_GESTURE
+                HOME_GESTURE -> ACTION_KEY
+                ACTION_KEY -> null
+            }
+        }
+    }
+
+    private object SingleScreenOnly : ScreenSequence {
+        override fun nextScreen(current: Screen): Screen? = null
+    }
 }
 
 enum class RequiredHardware {
     TOUCHPAD,
-    KEYBOARD
+    KEYBOARD,
 }
 
 enum class Screen(val requiredHardware: RequiredHardware) {
     BACK_GESTURE(requiredHardware = TOUCHPAD),
     HOME_GESTURE(requiredHardware = TOUCHPAD),
-    ACTION_KEY(requiredHardware = KEYBOARD);
-
-    fun next(): Screen? =
-        when (this) {
-            BACK_GESTURE -> HOME_GESTURE
-            HOME_GESTURE -> ACTION_KEY
-            ACTION_KEY -> null
-        }
+    ACTION_KEY(requiredHardware = KEYBOARD),
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/packages/SystemUI/src/com/android/systemui/keyboard/shared/model/ShortcutCustomizationRequestResult.kt
similarity index 74%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to packages/SystemUI/src/com/android/systemui/keyboard/shared/model/ShortcutCustomizationRequestResult.kt
index 7d3d8b9..bb563b1 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shared/model/ShortcutCustomizationRequestResult.kt
@@ -13,10 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package com.android.systemui.keyboard.shared.model
+
+enum class ShortcutCustomizationRequestResult {
+    SUCCESS,
+    ERROR_RESERVED_COMBINATION,
+    ERROR_OTHER,
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt
index da5590a..321fd57 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt
@@ -19,23 +19,34 @@
 import android.content.Context
 import android.content.Context.INPUT_SERVICE
 import android.hardware.input.InputGestureData
+import android.hardware.input.InputGestureData.Builder
 import android.hardware.input.InputGestureData.KeyTrigger
+import android.hardware.input.InputGestureData.createKeyTrigger
 import android.hardware.input.InputManager
+import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_ALREADY_EXISTS
+import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_RESERVED_GESTURE
+import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_SUCCESS
 import android.hardware.input.InputSettings
 import android.hardware.input.KeyGestureEvent
+import android.hardware.input.KeyGestureEvent.KeyGestureType
+import android.util.Log
+import androidx.annotation.VisibleForTesting
+import androidx.compose.runtime.mutableStateOf
 import com.android.systemui.Flags.shortcutHelperKeyGlyph
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.keyboard.shared.model.ShortcutCustomizationRequestResult
 import com.android.systemui.keyboard.shortcut.data.model.InternalKeyboardShortcutGroup
 import com.android.systemui.keyboard.shortcut.data.model.InternalKeyboardShortcutInfo
 import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState.Active
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
 import com.android.systemui.settings.UserTracker
 import javax.inject.Inject
-import kotlinx.coroutines.CoroutineDispatcher
+import kotlin.coroutines.CoroutineContext
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -52,9 +63,10 @@
     stateRepository: ShortcutHelperStateRepository,
     private val userTracker: UserTracker,
     @Background private val backgroundScope: CoroutineScope,
-    @Background private val backgroundDispatcher: CoroutineDispatcher,
+    @Background private val bgCoroutineContext: CoroutineContext,
     private val shortcutCategoriesUtils: ShortcutCategoriesUtils,
     private val context: Context,
+    private val inputGestureMaps: InputGestureMaps,
 ) : ShortcutCategoriesRepository {
 
     private val userContext: Context
@@ -66,11 +78,12 @@
         get() = userContext.getSystemService(INPUT_SERVICE) as InputManager
 
     private val _selectedKeyCombination = MutableStateFlow<KeyCombination?>(null)
+    private val _shortcutBeingCustomized = mutableStateOf<ShortcutCustomizationRequestInfo?>(null)
 
     private val activeInputDevice =
         stateRepository.state.map {
             if (it is Active) {
-                withContext(backgroundDispatcher) { inputManager.getInputDevice(it.deviceId) }
+                withContext(bgCoroutineContext) { inputManager.getInputDevice(it.deviceId) }
             } else {
                 null
             }
@@ -118,9 +131,7 @@
                     emptyList()
                 } else {
                     val customInputGesturesForUser: List<InputGestureData> =
-                        if (InputSettings.isCustomizableInputGesturesFeatureFlagEnabled()) {
-                            inputManager.getCustomInputGestures(/* filter= */ null)
-                        } else emptyList()
+                        getCustomInputGestures()
                     val sources = toInternalGroupSources(customInputGesturesForUser)
                     val supportedKeyCodes =
                         shortcutCategoriesUtils.fetchSupportedKeyCodes(
@@ -150,6 +161,150 @@
         _selectedKeyCombination.value = keyCombination
     }
 
+    fun onCustomizationRequested(requestInfo: ShortcutCustomizationRequestInfo?) {
+        _shortcutBeingCustomized.value = requestInfo
+    }
+
+    @VisibleForTesting
+    fun buildInputGestureDataForShortcutBeingCustomized(): InputGestureData? {
+        try {
+            return Builder()
+                .addKeyGestureTypeFromShortcutLabel()
+                .addTriggerFromSelectedKeyCombination()
+                .build()
+            // TODO(b/379648200) add app launch data after dynamic label/icon mapping implementation
+        } catch (e: IllegalArgumentException) {
+            Log.w(TAG, "could not add custom shortcut: $e")
+            return null
+        }
+    }
+
+    private fun retrieveInputGestureDataForShortcutBeingDeleted(): InputGestureData? {
+        val keyGestureType = getKeyGestureTypeFromShortcutBeingDeletedLabel()
+        return getCustomInputGestures().firstOrNull { it.action.keyGestureType() == keyGestureType }
+    }
+
+    suspend fun confirmAndSetShortcutCurrentlyBeingCustomized():
+        ShortcutCustomizationRequestResult {
+        return withContext(bgCoroutineContext) {
+            val inputGestureData =
+                buildInputGestureDataForShortcutBeingCustomized()
+                    ?: return@withContext ShortcutCustomizationRequestResult.ERROR_OTHER
+
+            return@withContext when (inputManager.addCustomInputGesture(inputGestureData)) {
+                CUSTOM_INPUT_GESTURE_RESULT_SUCCESS -> ShortcutCustomizationRequestResult.SUCCESS
+                CUSTOM_INPUT_GESTURE_RESULT_ERROR_ALREADY_EXISTS ->
+                    ShortcutCustomizationRequestResult.ERROR_RESERVED_COMBINATION
+
+                CUSTOM_INPUT_GESTURE_RESULT_ERROR_RESERVED_GESTURE ->
+                    ShortcutCustomizationRequestResult.ERROR_RESERVED_COMBINATION
+
+                else -> ShortcutCustomizationRequestResult.ERROR_OTHER
+            }
+        }
+    }
+
+    suspend fun deleteShortcutCurrentlyBeingCustomized():
+        ShortcutCustomizationRequestResult {
+        return withContext(bgCoroutineContext) {
+            val inputGestureData =
+                retrieveInputGestureDataForShortcutBeingDeleted()
+                    ?: return@withContext ShortcutCustomizationRequestResult.ERROR_OTHER
+            return@withContext when (
+                val result = inputManager.removeCustomInputGesture(inputGestureData)
+            ) {
+                CUSTOM_INPUT_GESTURE_RESULT_SUCCESS -> ShortcutCustomizationRequestResult.SUCCESS
+                else -> {
+                    Log.w(
+                        TAG,
+                        "Attempted to delete shortcut being customized " +
+                            "${_shortcutBeingCustomized.value} but ran into an error. InputGestureData" +
+                            " = $inputGestureData, error code: $result",
+                    )
+                    ShortcutCustomizationRequestResult.ERROR_OTHER
+                }
+            }
+        }
+    }
+
+    private fun getCustomInputGestures(): List<InputGestureData> {
+        return if (InputSettings.isCustomizableInputGesturesFeatureFlagEnabled()) {
+            inputManager.getCustomInputGestures(/* filter= */ InputGestureData.Filter.KEY)
+        } else emptyList()
+    }
+
+    private fun Builder.addKeyGestureTypeFromShortcutLabel(): Builder {
+        val keyGestureType = getKeyGestureTypeFromShortcutBeingCustomizedLabel()
+
+        if (keyGestureType == null) {
+            Log.w(
+                TAG,
+                "Could not find KeyGestureType for shortcut ${_shortcutBeingCustomized.value}",
+            )
+            return this
+        }
+
+        return setKeyGestureType(keyGestureType)
+    }
+
+    @KeyGestureType
+    private fun getKeyGestureTypeFromShortcutBeingCustomizedLabel(): Int? {
+        val shortcutBeingCustomized =
+            getShortcutBeingCustomized() as? ShortcutCustomizationRequestInfo.Add
+
+        if (shortcutBeingCustomized == null) {
+            Log.w(
+                TAG,
+                "Requested key gesture type from label but shortcut being customized is null",
+            )
+            return null
+        }
+
+        return inputGestureMaps.shortcutLabelToKeyGestureTypeMap[shortcutBeingCustomized.label]
+    }
+
+    @KeyGestureType
+    private fun getKeyGestureTypeFromShortcutBeingDeletedLabel(): Int? {
+        val shortcutBeingCustomized =
+            getShortcutBeingCustomized() as? ShortcutCustomizationRequestInfo.Delete
+
+        if (shortcutBeingCustomized == null) {
+            Log.w(
+                TAG,
+                "Requested key gesture type from label but shortcut being customized is null",
+            )
+            return null
+        }
+
+        return inputGestureMaps.shortcutLabelToKeyGestureTypeMap[shortcutBeingCustomized.label]
+    }
+
+    private fun Builder.addTriggerFromSelectedKeyCombination(): Builder {
+        val selectedKeyCombination = _selectedKeyCombination.value
+        if (selectedKeyCombination?.keyCode == null) {
+            Log.w(
+                TAG,
+                "User requested to set shortcut but selected key combination is " +
+                    "$selectedKeyCombination",
+            )
+            return this
+        }
+
+        return setTrigger(
+            createKeyTrigger(
+                /* keycode = */ selectedKeyCombination.keyCode,
+                /* modifierState = */ shortcutCategoriesUtils.removeUnsupportedModifiers(
+                    selectedKeyCombination.modifiers
+                ),
+            )
+        )
+    }
+
+    @VisibleForTesting
+    fun getShortcutBeingCustomized(): ShortcutCustomizationRequestInfo? {
+        return _shortcutBeingCustomized.value
+    }
+
     private fun toInternalGroupSources(
         inputGestures: List<InputGestureData>
     ): List<InternalGroupsSource> {
@@ -194,7 +349,7 @@
     private fun fetchGroupLabelByGestureType(
         @KeyGestureEvent.KeyGestureType keyGestureType: Int
     ): String? {
-        InputGestures.gestureToInternalKeyboardShortcutGroupLabelResIdMap[keyGestureType]?.let {
+        inputGestureMaps.gestureToInternalKeyboardShortcutGroupLabelResIdMap[keyGestureType]?.let {
             return context.getString(it)
         } ?: return null
     }
@@ -202,7 +357,7 @@
     private fun fetchShortcutInfoLabelByGestureType(
         @KeyGestureEvent.KeyGestureType keyGestureType: Int
     ): String? {
-        InputGestures.gestureToInternalKeyboardShortcutInfoLabelResIdMap[keyGestureType]?.let {
+        inputGestureMaps.gestureToInternalKeyboardShortcutInfoLabelResIdMap[keyGestureType]?.let {
             return context.getString(it)
         } ?: return null
     }
@@ -210,11 +365,15 @@
     private fun fetchShortcutCategoryTypeByGestureType(
         @KeyGestureEvent.KeyGestureType keyGestureType: Int
     ): ShortcutCategoryType? {
-        return InputGestures.gestureToShortcutCategoryTypeMap[keyGestureType]
+        return inputGestureMaps.gestureToShortcutCategoryTypeMap[keyGestureType]
     }
 
     private data class InternalGroupsSource(
         val groups: List<InternalKeyboardShortcutGroup>,
         val type: ShortcutCategoryType,
     )
+
+    private companion object {
+        private const val TAG = "CustomShortcutCategoriesRepository"
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestures.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestures.kt
rename to packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt
index 7bb294d..ecc0761 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestures.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.keyboard.shortcut.data.repository
 
+import android.content.Context
 import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS
 import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_BACK
 import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT
@@ -45,8 +46,9 @@
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MultiTasking
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.System
 import com.android.systemui.res.R
+import javax.inject.Inject
 
-object InputGestures {
+class InputGestureMaps @Inject constructor(private val context: Context) {
     val gestureToShortcutCategoryTypeMap =
         mapOf(
             // System Category
@@ -174,4 +176,12 @@
             KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING to
                 R.string.keyboard_shortcut_group_applications_sms,
         )
+
+    val shortcutLabelToKeyGestureTypeMap: Map<String, Int>
+        get() =
+            gestureToInternalKeyboardShortcutInfoLabelResIdMap.entries.associateBy({
+                context.getString(it.value)
+            }) {
+                it.key
+            }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutCategoriesUtils.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutCategoriesUtils.kt
index 3988d1f1..27d1a30 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutCategoriesUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutCategoriesUtils.kt
@@ -47,6 +47,11 @@
     @Background private val backgroundCoroutineContext: CoroutineContext,
     private val inputManager: InputManager,
 ) {
+
+    fun removeUnsupportedModifiers(modifierMask: Int): Int {
+        return SUPPORTED_MODIFIERS.reduce { acc, modifier -> acc or modifier } and modifierMask
+    }
+
     fun fetchShortcutCategory(
         type: ShortcutCategoryType?,
         groups: List<InternalKeyboardShortcutGroup>,
@@ -111,7 +116,10 @@
             .filter {
                 // Allow KEYCODE_UNKNOWN (0) because shortcuts can have just modifiers and no
                 // keycode, or they could have a baseCharacter instead of a keycode.
-                it.keycode == KeyEvent.KEYCODE_UNKNOWN || supportedKeyCodes.contains(it.keycode)
+                it.keycode == KeyEvent.KEYCODE_UNKNOWN ||
+                    supportedKeyCodes.contains(it.keycode) ||
+                    // Support keyboard function row key codes
+                    keyGlyphMap?.functionRowKeys?.contains(it.keycode) ?: false
             }
             .mapNotNull { toShortcut(keyGlyphMap, keyCharacterMap, it, keepIcons) }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt
index e47b33f..d91922d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt
@@ -99,6 +99,7 @@
 import android.view.KeyEvent.KEYCODE_PAGE_UP
 import android.view.KeyEvent.KEYCODE_PERIOD
 import android.view.KeyEvent.KEYCODE_RECENT_APPS
+import android.view.KeyEvent.KEYCODE_SCREENSHOT
 import android.view.KeyEvent.KEYCODE_SCROLL_LOCK
 import android.view.KeyEvent.KEYCODE_SHIFT_LEFT
 import android.view.KeyEvent.KEYCODE_SHIFT_RIGHT
@@ -125,6 +126,14 @@
             KEYCODE_RECENT_APPS to R.drawable.ic_check_box_outline_blank,
         )
 
+    val keyLabelResIds =
+        mapOf(
+            KEYCODE_BACK to R.string.group_system_go_back,
+            KEYCODE_HOME to R.string.group_system_access_home_screen,
+            KEYCODE_RECENT_APPS to R.string.group_system_overview_open_apps,
+            KEYCODE_SCREENSHOT to R.string.group_system_full_screenshot,
+        )
+
     val modifierLabels =
         mapOf<Int, (Context) -> String>(
             // Modifiers
@@ -140,6 +149,7 @@
         mapOf<Int, (Context) -> String>(
             KEYCODE_HOME to { context -> context.getString(R.string.keyboard_key_home) },
             KEYCODE_BACK to { context -> context.getString(R.string.keyboard_key_back) },
+            KEYCODE_RECENT_APPS to { context -> context.getString(R.string.accessibility_recent) },
             KEYCODE_DPAD_UP to { context -> context.getString(R.string.keyboard_key_dpad_up) },
             KEYCODE_DPAD_DOWN to { context -> context.getString(R.string.keyboard_key_dpad_down) },
             KEYCODE_DPAD_LEFT to { context -> context.getString(R.string.keyboard_key_dpad_left) },
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSource.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSource.kt
index 1b20986..4787507 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSource.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSource.kt
@@ -17,12 +17,16 @@
 package com.android.systemui.keyboard.shortcut.data.source
 
 import android.content.res.Resources
+import android.hardware.input.InputManager
+import android.view.KeyEvent.KEYCODE_EMOJI_PICKER
 import android.view.KeyEvent.KEYCODE_SPACE
 import android.view.KeyEvent.META_CTRL_ON
 import android.view.KeyEvent.META_SHIFT_ON
 import android.view.KeyboardShortcutGroup
+import android.view.KeyboardShortcutInfo
 import android.view.WindowManager
 import android.view.WindowManager.KeyboardShortcutsReceiver
+import com.android.systemui.Flags.shortcutHelperKeyGlyph
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.keyboard.shortcut.data.model.shortcutInfo
 import com.android.systemui.res.R
@@ -31,16 +35,19 @@
 
 class InputShortcutsSource
 @Inject
-constructor(@Main private val resources: Resources, private val windowManager: WindowManager) :
-    KeyboardShortcutGroupsSource {
+constructor(
+    @Main private val resources: Resources,
+    private val windowManager: WindowManager,
+    private val inputManager: InputManager,
+) : KeyboardShortcutGroupsSource {
     override suspend fun shortcutGroups(deviceId: Int): List<KeyboardShortcutGroup> =
-        getInputLanguageShortcutGroup() + getImeShortcutGroup(deviceId)
+        getInputLanguageShortcutGroup(deviceId) + getImeShortcutGroup(deviceId)
 
-    private fun getInputLanguageShortcutGroup() =
+    private fun getInputLanguageShortcutGroup(deviceId: Int) =
         listOf(
             KeyboardShortcutGroup(
                 resources.getString(R.string.shortcut_helper_category_input),
-                inputLanguageShortcuts()
+                inputLanguageShortcuts() + hardwareShortcuts(deviceId),
             )
         )
 
@@ -53,9 +60,23 @@
             /* Switch previous language (next language): Ctrl + Shift + Space */
             shortcutInfo(resources.getString(R.string.input_switch_input_language_previous)) {
                 command(META_CTRL_ON or META_SHIFT_ON, KEYCODE_SPACE)
-            }
+            },
         )
 
+    private fun hardwareShortcuts(deviceId: Int): List<KeyboardShortcutInfo> {
+        if (shortcutHelperKeyGlyph()) {
+            val keyGlyphMap = inputManager.getKeyGlyphMap(deviceId)
+            if (keyGlyphMap != null && keyGlyphMap.functionRowKeys.contains(KEYCODE_EMOJI_PICKER)) {
+                return listOf(
+                    shortcutInfo(resources.getString(R.string.input_access_emoji)) {
+                        command(modifiers = 0, KEYCODE_EMOJI_PICKER)
+                    }
+                )
+            }
+        }
+        return emptyList()
+    }
+
     private suspend fun getImeShortcutGroup(deviceId: Int): List<KeyboardShortcutGroup> =
         suspendCancellableCoroutine { continuation ->
             val shortcutsReceiver = KeyboardShortcutsReceiver {
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt
index 0201f40..5ef869e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt
@@ -16,24 +16,34 @@
 
 package com.android.systemui.keyboard.shortcut.data.source
 
+import android.content.Context
 import android.content.res.Resources
 import android.view.KeyEvent.KEYCODE_D
 import android.view.KeyEvent.KEYCODE_DPAD_LEFT
 import android.view.KeyEvent.KEYCODE_DPAD_RIGHT
 import android.view.KeyEvent.KEYCODE_DPAD_UP
+import android.view.KeyEvent.KEYCODE_EQUALS
+import android.view.KeyEvent.KEYCODE_LEFT_BRACKET
+import android.view.KeyEvent.KEYCODE_MINUS
+import android.view.KeyEvent.KEYCODE_RIGHT_BRACKET
 import android.view.KeyEvent.KEYCODE_TAB
 import android.view.KeyEvent.META_ALT_ON
 import android.view.KeyEvent.META_CTRL_ON
 import android.view.KeyEvent.META_META_ON
 import android.view.KeyEvent.META_SHIFT_ON
 import android.view.KeyboardShortcutGroup
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.keyboard.shortcut.data.model.shortcutInfo
 import com.android.systemui.res.R
 import com.android.window.flags.Flags.enableMoveToNextDisplayShortcut
+import com.android.window.flags.Flags.enableTaskResizingKeyboardShortcuts
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
 import javax.inject.Inject
 
-class MultitaskingShortcutsSource @Inject constructor(@Main private val resources: Resources) :
+class MultitaskingShortcutsSource
+@Inject
+constructor(@Main private val resources: Resources, @Application private val context: Context) :
     KeyboardShortcutGroupsSource {
 
     override suspend fun shortcutGroups(deviceId: Int) =
@@ -95,6 +105,40 @@
                 }
             )
         }
+        if (
+            DesktopModeStatus.canEnterDesktopMode(context) && enableTaskResizingKeyboardShortcuts()
+        ) {
+            // Snap a freeform window to the left
+            //  - Meta + Left bracket
+            add(
+                shortcutInfo(resources.getString(R.string.system_desktop_mode_snap_left_window)) {
+                    command(META_META_ON, KEYCODE_LEFT_BRACKET)
+                }
+            )
+            // Snap a freeform window to the right
+            //  - Meta + Right bracket
+            add(
+                shortcutInfo(resources.getString(R.string.system_desktop_mode_snap_right_window)) {
+                    command(META_META_ON, KEYCODE_RIGHT_BRACKET)
+                }
+            )
+            // Toggle maximize a freeform window
+            //  - Meta + Equals
+            add(
+                shortcutInfo(
+                    resources.getString(R.string.system_desktop_mode_toggle_maximize_window)
+                ) {
+                    command(META_META_ON, KEYCODE_EQUALS)
+                }
+            )
+            // Minimize a freeform window
+            //  - Meta + Minus
+            add(
+                shortcutInfo(resources.getString(R.string.system_desktop_mode_minimize_window)) {
+                    command(META_META_ON, KEYCODE_MINUS)
+                }
+            )
+        }
     }
 
     private fun recentsShortcuts() =
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt
index 7c0c75e..a650cd8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt
@@ -17,6 +17,8 @@
 package com.android.systemui.keyboard.shortcut.data.source
 
 import android.content.res.Resources
+import android.hardware.input.InputManager
+import android.hardware.input.KeyGlyphMap
 import android.view.KeyEvent.KEYCODE_A
 import android.view.KeyEvent.KEYCODE_BACK
 import android.view.KeyEvent.KEYCODE_DEL
@@ -35,26 +37,87 @@
 import android.view.KeyEvent.META_CTRL_ON
 import android.view.KeyEvent.META_META_ON
 import android.view.KeyboardShortcutGroup
+import android.view.KeyboardShortcutInfo
+import com.android.systemui.Flags.shortcutHelperKeyGlyph
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.keyboard.shortcut.data.model.shortcutInfo
+import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperKeys
 import com.android.systemui.res.R
 import javax.inject.Inject
 
-class SystemShortcutsSource @Inject constructor(@Main private val resources: Resources) :
+class SystemShortcutsSource
+@Inject
+constructor(@Main private val resources: Resources, private val inputManager: InputManager) :
     KeyboardShortcutGroupsSource {
 
     override suspend fun shortcutGroups(deviceId: Int) =
         listOf(
             KeyboardShortcutGroup(
                 resources.getString(R.string.shortcut_helper_category_system_controls),
-                systemControlsShortcuts()
+                hardwareShortcuts(deviceId) + systemControlsShortcuts(),
             ),
             KeyboardShortcutGroup(
                 resources.getString(R.string.shortcut_helper_category_system_apps),
-                systemAppsShortcuts()
-            )
+                systemAppsShortcuts(),
+            ),
         )
 
+    private fun hardwareShortcuts(deviceId: Int): List<KeyboardShortcutInfo> =
+        if (shortcutHelperKeyGlyph()) {
+            val keyGlyphMap = inputManager.getKeyGlyphMap(deviceId)
+            if (keyGlyphMap != null) {
+                functionRowKeys(keyGlyphMap) + keyCombinationShortcuts(keyGlyphMap)
+            } else {
+                // Not add function row keys if it is not supported by keyboard
+                emptyList()
+            }
+        } else {
+            defaultFunctionRowKeys()
+        }
+
+    private fun defaultFunctionRowKeys(): List<KeyboardShortcutInfo> =
+        listOf(
+            shortcutInfo(resources.getString(R.string.group_system_access_home_screen)) {
+                command(modifiers = 0, KEYCODE_HOME)
+            },
+            shortcutInfo(resources.getString(R.string.group_system_go_back)) {
+                command(modifiers = 0, KEYCODE_BACK)
+            },
+            shortcutInfo(resources.getString(R.string.group_system_overview_open_apps)) {
+                command(modifiers = 0, KEYCODE_RECENT_APPS)
+            },
+        )
+
+    private fun functionRowKeys(keyGlyphMap: KeyGlyphMap): List<KeyboardShortcutInfo> {
+        val functionRowKeys = mutableListOf<KeyboardShortcutInfo>()
+        keyGlyphMap.functionRowKeys.forEach { keyCode ->
+            val labelResId = ShortcutHelperKeys.keyLabelResIds[keyCode]
+            if (labelResId != null) {
+                functionRowKeys.add(
+                    shortcutInfo(resources.getString(labelResId)) {
+                        command(modifiers = 0, keyCode)
+                    }
+                )
+            }
+        }
+        return functionRowKeys
+    }
+
+    private fun keyCombinationShortcuts(keyGlyphMap: KeyGlyphMap): List<KeyboardShortcutInfo> {
+        val shortcuts = mutableListOf<KeyboardShortcutInfo>()
+        keyGlyphMap.hardwareShortcuts.forEach { (keyCombination, keyCode) ->
+            val labelResId = ShortcutHelperKeys.keyLabelResIds[keyCode]
+            if (labelResId != null) {
+                val info =
+                    shortcutInfo(resources.getString(labelResId)) {
+                        command(keyCombination.modifierState, keyCombination.keycode)
+                    }
+                shortcuts.add(info)
+            }
+        }
+        return shortcuts
+    }
+
     private fun systemControlsShortcuts() =
         listOf(
             // Access list of all apps and search (i.e. Search/Launcher):
@@ -63,36 +126,24 @@
                 command(META_META_ON)
             },
             // Access home screen:
-            //  - Home button
             //  - Meta + H
             //  - Meta + Enter
             shortcutInfo(resources.getString(R.string.group_system_access_home_screen)) {
-                command(modifiers = 0, KEYCODE_HOME)
-            },
-            shortcutInfo(resources.getString(R.string.group_system_access_home_screen)) {
                 command(META_META_ON, KEYCODE_H)
             },
             shortcutInfo(resources.getString(R.string.group_system_access_home_screen)) {
                 command(META_META_ON, KEYCODE_ENTER)
             },
             // Overview of open apps:
-            //  - Recent apps button
             //  - Meta + Tab
             shortcutInfo(resources.getString(R.string.group_system_overview_open_apps)) {
-                command(modifiers = 0, KEYCODE_RECENT_APPS)
-            },
-            shortcutInfo(resources.getString(R.string.group_system_overview_open_apps)) {
                 command(META_META_ON, KEYCODE_TAB)
             },
             // Back: go back to previous state (back button)
-            //  - Back button
             //  - Meta + Escape OR
             //  - Meta + Backspace OR
             //  - Meta + Left arrow
             shortcutInfo(resources.getString(R.string.group_system_go_back)) {
-                command(modifiers = 0, KEYCODE_BACK)
-            },
-            shortcutInfo(resources.getString(R.string.group_system_go_back)) {
                 command(META_META_ON, KEYCODE_ESCAPE)
             },
             shortcutInfo(resources.getString(R.string.group_system_go_back)) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt
index aad55dc..7743c53 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt
@@ -16,9 +16,11 @@
 
 package com.android.systemui.keyboard.shortcut.domain.interactor
 
+import com.android.systemui.keyboard.shared.model.ShortcutCustomizationRequestResult
 import com.android.systemui.keyboard.shortcut.data.repository.CustomShortcutCategoriesRepository
 import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperKeys
 import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
 import javax.inject.Inject
 
@@ -34,4 +36,18 @@
     fun getDefaultCustomShortcutModifierKey(): ShortcutKey.Icon.ResIdIcon {
         return ShortcutKey.Icon.ResIdIcon(ShortcutHelperKeys.metaModifierIconResId)
     }
+
+    fun onCustomizationRequested(requestInfo: ShortcutCustomizationRequestInfo?) {
+        customShortcutRepository.onCustomizationRequested(requestInfo)
+    }
+
+    suspend fun confirmAndSetShortcutCurrentlyBeingCustomized():
+        ShortcutCustomizationRequestResult {
+        return customShortcutRepository.confirmAndSetShortcutCurrentlyBeingCustomized()
+    }
+
+    suspend fun deleteShortcutCurrentlyBeingCustomized():
+        ShortcutCustomizationRequestResult {
+        return customShortcutRepository.deleteShortcutCurrentlyBeingCustomized()
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt
index 0381eae..2385cc6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt
@@ -16,14 +16,22 @@
 
 package com.android.systemui.keyboard.shortcut.domain.interactor
 
+import android.content.Context
+import android.view.KeyEvent.META_META_ON
 import com.android.systemui.Flags.keyboardShortcutHelperShortcutCustomizer
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyboard.shortcut.data.repository.ShortcutCategoriesRepository
+import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperKeys
+import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperKeys.metaModifierIconResId
 import com.android.systemui.keyboard.shortcut.qualifiers.CustomShortcutCategories
 import com.android.systemui.keyboard.shortcut.qualifiers.DefaultShortcutCategories
 import com.android.systemui.keyboard.shortcut.shared.model.Shortcut
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
+import com.android.systemui.res.R
 import dagger.Lazy
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
@@ -34,6 +42,7 @@
 class ShortcutHelperCategoriesInteractor
 @Inject
 constructor(
+    @Application private val context: Context,
     @DefaultShortcutCategories defaultCategoriesRepository: ShortcutCategoriesRepository,
     @CustomShortcutCategories customCategoriesRepositoryLazy: Lazy<ShortcutCategoriesRepository>,
 ) {
@@ -87,6 +96,54 @@
                     label = commonLabel,
                     icon = groupedShortcuts.firstOrNull()?.icon,
                     commands = groupedShortcuts.flatMap { it.commands },
+                    contentDescription =
+                        toContentDescription(commonLabel, groupedShortcuts.flatMap { it.commands }),
                 )
             }
+
+    private fun toContentDescription(label: String, commands: List<ShortcutCommand>): String {
+        val pressKey = context.getString(R.string.shortcut_helper_add_shortcut_dialog_placeholder)
+        val andConjunction =
+            context.getString(R.string.shortcut_helper_key_combinations_and_conjunction)
+        val orConjunction =
+            context.getString(R.string.shortcut_helper_key_combinations_or_separator)
+        val forwardSlash =
+            context.getString(R.string.shortcut_helper_key_combinations_forward_slash)
+        return buildString {
+            append("$label, $pressKey")
+            commands.forEachIndexed { i, shortcutCommand ->
+                if (i > 0) {
+                    append(", $orConjunction")
+                }
+                shortcutCommand.keys.forEachIndexed { j, shortcutKey ->
+                    if (j > 0) {
+                        append(" $andConjunction")
+                    }
+                    if (shortcutKey is ShortcutKey.Text) {
+                        // Special handling for "/" as TalkBack will not read punctuation by
+                        // default.
+                        if (shortcutKey.value.equals("/")) {
+                            append(" $forwardSlash")
+                        } else {
+                            append(" ${shortcutKey.value}")
+                        }
+                    } else if (shortcutKey is ShortcutKey.Icon.ResIdIcon) {
+                        val keyLabel =
+                            if (shortcutKey.drawableResId == metaModifierIconResId) {
+                                ShortcutHelperKeys.modifierLabels[META_META_ON]
+                            } else {
+                                val keyCode =
+                                    ShortcutHelperKeys.keyIcons.entries
+                                        .firstOrNull { it.value == shortcutKey.drawableResId }
+                                        ?.key
+                                ShortcutHelperKeys.specialKeyLabels[keyCode]
+                            }
+                        if (keyLabel != null) {
+                            append(" ${keyLabel.invoke(context)}")
+                        }
+                    } // No-Op when shortcutKey is ShortcutKey.Icon.DrawableIcon
+                }
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt
index bf7df7e..9cc15ce 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt
@@ -20,18 +20,24 @@
     val label: String,
     val commands: List<ShortcutCommand>,
     val icon: ShortcutIcon? = null,
+    val contentDescription: String = "",
 ) {
     val containsCustomShortcutCommands: Boolean = commands.any { it.isCustom }
 }
 
 class ShortcutBuilder(private val label: String) {
     val commands = mutableListOf<ShortcutCommand>()
+    var contentDescription = ""
 
     fun command(builder: ShortcutCommandBuilder.() -> Unit) {
         commands += ShortcutCommandBuilder().apply(builder).build()
     }
 
-    fun build() = Shortcut(label, commands)
+    fun contentDescription(string: () -> String) {
+        contentDescription = string.invoke()
+    }
+
+    fun build() = Shortcut(label, commands, contentDescription = contentDescription)
 }
 
 fun shortcut(label: String, block: ShortcutBuilder.() -> Unit): Shortcut =
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt
index 813a1fca..4648053 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt
@@ -18,25 +18,31 @@
 
 sealed interface ShortcutCategoryType {
     val isTrusted: Boolean
+    val includeInCustomization: Boolean
 
     data object System : ShortcutCategoryType {
         override val isTrusted: Boolean = true
+        override val includeInCustomization: Boolean = true
     }
 
     data object MultiTasking : ShortcutCategoryType {
         override val isTrusted: Boolean = true
+        override val includeInCustomization: Boolean = true
     }
 
     data object InputMethodEditor : ShortcutCategoryType {
         override val isTrusted: Boolean = false
+        override val includeInCustomization: Boolean = false
     }
 
     data object AppCategories : ShortcutCategoryType {
         override val isTrusted: Boolean = true
+        override val includeInCustomization: Boolean = true
     }
 
     data class CurrentApp(val packageName: String) : ShortcutCategoryType {
         override val isTrusted: Boolean = false
+        override val includeInCustomization: Boolean = false
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCustomizationRequestInfo.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCustomizationRequestInfo.kt
index 203228b..2d3e7f6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCustomizationRequestInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCustomizationRequestInfo.kt
@@ -18,8 +18,14 @@
 
 sealed interface ShortcutCustomizationRequestInfo {
     data class Add(
-        val label: String,
-        val categoryType: ShortcutCategoryType,
-        val subCategoryLabel: String,
+        val label: String = "",
+        val categoryType: ShortcutCategoryType = ShortcutCategoryType.System,
+        val subCategoryLabel: String = "",
+    ) : ShortcutCustomizationRequestInfo
+
+    data class Delete(
+        val label: String = "",
+        val categoryType: ShortcutCategoryType = ShortcutCategoryType.System,
+        val subCategoryLabel: String = "",
     ) : ShortcutCustomizationRequestInfo
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
index 2cb822e..f28618b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
@@ -22,12 +22,15 @@
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.layout.wrapContentHeight
 import androidx.compose.runtime.getValue
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
-import com.android.systemui.keyboard.shortcut.ui.composable.AssignNewShortcutDialog
+import com.android.systemui.keyboard.shortcut.ui.composable.ShortcutCustomizationDialog
 import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState
+import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState.AddShortcutDialog
+import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState.DeleteShortcutDialog
 import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutCustomizationViewModel
 import com.android.systemui.lifecycle.ExclusiveActivatable
 import com.android.systemui.statusbar.phone.SystemUIDialogFactory
@@ -35,6 +38,7 @@
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.launch
 
 class ShortcutCustomizationDialogStarter
 @AssistedInject
@@ -48,12 +52,11 @@
 
     override suspend fun onActivated(): Nothing {
         viewModel.shortcutCustomizationUiState.collect { uiState ->
-            if (
-                uiState is ShortcutCustomizationUiState.AddShortcutDialog &&
-                !uiState.isDialogShowing
-            ) {
-                dialog = createAddShortcutDialog().also { it.show() }
-                viewModel.onAddShortcutDialogShown()
+            val shouldShowAddDialog = uiState is AddShortcutDialog && !uiState.isDialogShowing
+            val shouldShowDeleteDialog = uiState is DeleteShortcutDialog && !uiState.isDialogShowing
+            if (shouldShowDeleteDialog || shouldShowAddDialog) {
+                dialog = createDialog().also { it.show() }
+                viewModel.onDialogShown()
             } else if (uiState is ShortcutCustomizationUiState.Inactive) {
                 dialog?.dismiss()
                 dialog = null
@@ -66,18 +69,21 @@
         viewModel.onShortcutCustomizationRequested(requestInfo)
     }
 
-    private fun createAddShortcutDialog(): Dialog {
+    private fun createDialog(): Dialog {
         return dialogFactory.create(dialogDelegate = ShortcutCustomizationDialogDelegate()) { dialog
             ->
             val uiState by
                 viewModel.shortcutCustomizationUiState.collectAsStateWithLifecycle(
                     initialValue = ShortcutCustomizationUiState.Inactive
                 )
-            AssignNewShortcutDialog(
+            val coroutineScope = rememberCoroutineScope()
+            ShortcutCustomizationDialog(
                 uiState = uiState,
                 modifier = Modifier.width(364.dp).wrapContentHeight().padding(vertical = 24.dp),
                 onKeyPress = { viewModel.onKeyPressed(it) },
                 onCancel = { dialog.dismiss() },
+                onConfirmSetShortcut = { coroutineScope.launch { viewModel.onSetShortcut() } },
+                onConfirmDeleteShortcut = { coroutineScope.launch { viewModel.deleteShortcutCurrentlyBeingCustomized() } },
             )
             dialog.setOnDismissListener { viewModel.onDialogDismissed() }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt
index d722933..20040c6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt
@@ -61,41 +61,85 @@
 import com.android.systemui.res.R
 
 @Composable
-fun AssignNewShortcutDialog(
+fun ShortcutCustomizationDialog(
     uiState: ShortcutCustomizationUiState,
     modifier: Modifier = Modifier,
     onKeyPress: (KeyEvent) -> Boolean,
     onCancel: () -> Unit,
+    onConfirmSetShortcut: () -> Unit,
+    onConfirmDeleteShortcut: () -> Unit,
 ) {
-    if (uiState is ShortcutCustomizationUiState.AddShortcutDialog) {
-        Column(modifier = modifier) {
-            Title(
-                uiState.shortcutLabel,
-                modifier = Modifier.padding(horizontal = 24.dp).width(316.dp),
-            )
-            Description(
-                modifier = Modifier.padding(top = 24.dp, start = 24.dp, end = 24.dp).width(316.dp)
-            )
-            PromptShortcutModifier(
-                modifier =
-                    Modifier.padding(top = 24.dp, start = 116.5.dp, end = 116.5.dp)
-                        .width(131.dp)
-                        .height(48.dp),
-                defaultModifierKey = uiState.defaultCustomShortcutModifierKey,
-            )
-            SelectedKeyCombinationContainer(
-                shouldShowErrorMessage = uiState.shouldShowErrorMessage,
-                onKeyPress = onKeyPress,
-                pressedKeys = uiState.pressedKeys,
-            )
-            KeyCombinationAlreadyInUseErrorMessage(uiState.shouldShowErrorMessage)
-            DialogButtons(onCancel, isSetShortcutButtonEnabled = uiState.pressedKeys.isNotEmpty())
+    when (uiState) {
+        is ShortcutCustomizationUiState.AddShortcutDialog -> {
+            Column(modifier = modifier) {
+                Title(uiState.shortcutLabel)
+                Description(
+                    text =
+                        stringResource(
+                            id = R.string.shortcut_customize_mode_add_shortcut_description
+                        )
+                )
+                PromptShortcutModifier(
+                    modifier =
+                        Modifier.padding(top = 24.dp, start = 116.5.dp, end = 116.5.dp)
+                            .width(131.dp)
+                            .height(48.dp),
+                    defaultModifierKey = uiState.defaultCustomShortcutModifierKey,
+                )
+                SelectedKeyCombinationContainer(
+                    shouldShowError = uiState.errorMessage.isNotEmpty(),
+                    onKeyPress = onKeyPress,
+                    pressedKeys = uiState.pressedKeys,
+                )
+                ErrorMessageContainer(uiState.errorMessage)
+                DialogButtons(
+                    onCancel,
+                    isConfirmButtonEnabled = uiState.pressedKeys.isNotEmpty(),
+                    onConfirm = onConfirmSetShortcut,
+                    confirmButtonText =
+                        stringResource(
+                            R.string.shortcut_helper_customize_dialog_set_shortcut_button_label
+                        ),
+                )
+            }
+        }
+        is ShortcutCustomizationUiState.DeleteShortcutDialog -> {
+            Column(modifier) {
+                Title(
+                    title =
+                        stringResource(
+                            id = R.string.shortcut_customize_mode_remove_shortcut_dialog_title
+                        )
+                )
+                Description(
+                    text =
+                        stringResource(
+                            id = R.string.shortcut_customize_mode_remove_shortcut_description
+                        )
+                )
+                DialogButtons(
+                    onCancel = onCancel,
+                    onConfirm = onConfirmDeleteShortcut,
+                    confirmButtonText =
+                        stringResource(
+                            R.string.shortcut_helper_customize_dialog_remove_button_label
+                        ),
+                )
+            }
+        }
+        else -> {
+            /* No-Op */
         }
     }
 }
 
 @Composable
-fun DialogButtons(onCancel: () -> Unit, isSetShortcutButtonEnabled: Boolean) {
+fun DialogButtons(
+    onCancel: () -> Unit,
+    isConfirmButtonEnabled: Boolean = true,
+    onConfirm: () -> Unit,
+    confirmButtonText: String,
+) {
     Row(
         modifier =
             Modifier.padding(top = 24.dp, start = 24.dp, end = 24.dp)
@@ -113,23 +157,22 @@
         )
         Spacer(modifier = Modifier.width(8.dp))
         ShortcutHelperButton(
-            onClick = {},
+            onClick = onConfirm,
             color = MaterialTheme.colorScheme.primary,
             width = 116.dp,
             contentColor = MaterialTheme.colorScheme.onPrimary,
-            text =
-                stringResource(R.string.shortcut_helper_customize_dialog_set_shortcut_button_label),
-            enabled = isSetShortcutButtonEnabled,
+            text = confirmButtonText,
+            enabled = isConfirmButtonEnabled,
         )
     }
 }
 
 @Composable
-fun KeyCombinationAlreadyInUseErrorMessage(shouldShowErrorMessage: Boolean) {
-    if (shouldShowErrorMessage) {
+fun ErrorMessageContainer(errorMessage: String) {
+    if (errorMessage.isNotEmpty()) {
         Box(modifier = Modifier.padding(horizontal = 16.dp).width(332.dp).height(40.dp)) {
             Text(
-                text = stringResource(R.string.shortcut_helper_customize_dialog_error_message),
+                text = errorMessage,
                 style = MaterialTheme.typography.bodyMedium,
                 fontSize = 14.sp,
                 lineHeight = 20.sp,
@@ -143,7 +186,7 @@
 
 @Composable
 fun SelectedKeyCombinationContainer(
-    shouldShowErrorMessage: Boolean,
+    shouldShowError: Boolean,
     onKeyPress: (KeyEvent) -> Boolean,
     pressedKeys: List<ShortcutKey>,
 ) {
@@ -151,7 +194,7 @@
     val isFocused by interactionSource.collectIsFocusedAsState()
     val outlineColor =
         if (!isFocused) MaterialTheme.colorScheme.outline
-        else if (shouldShowErrorMessage) MaterialTheme.colorScheme.error
+        else if (shouldShowError) MaterialTheme.colorScheme.error
         else MaterialTheme.colorScheme.primary
     val focusRequester = remember { FocusRequester() }
 
@@ -179,7 +222,7 @@
                 PressedKeysTextContainer(pressedKeys)
             }
             Spacer(modifier = Modifier.weight(1f))
-            if (shouldShowErrorMessage) {
+            if (shouldShowError) {
                 Icon(
                     imageVector = Icons.Default.ErrorOutline,
                     contentDescription = null,
@@ -253,23 +296,28 @@
 }
 
 @Composable
-private fun Title(title: String, modifier: Modifier = Modifier) {
+private fun Title(title: String) {
     Text(
         text = title,
         style = MaterialTheme.typography.headlineSmall,
         fontSize = 24.sp,
-        modifier = modifier.wrapContentSize(Alignment.Center),
+        modifier =
+            Modifier.padding(horizontal = 24.dp).width(316.dp).wrapContentSize(Alignment.Center),
         color = MaterialTheme.colorScheme.onSurface,
         lineHeight = 32.sp,
+        fontWeight = FontWeight.W400,
     )
 }
 
 @Composable
-private fun Description(modifier: Modifier = Modifier) {
+private fun Description(text: String) {
     Text(
-        text = stringResource(id = R.string.shortcut_helper_customize_mode_sub_title),
+        text = text,
         style = MaterialTheme.typography.bodyMedium,
-        modifier = modifier.wrapContentSize(Alignment.Center),
+        modifier =
+            Modifier.padding(top = 24.dp, start = 24.dp, end = 24.dp)
+                .width(316.dp)
+                .wrapContentSize(Alignment.Center),
         color = MaterialTheme.colorScheme.onSurfaceVariant,
     )
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
index b6b5d17..1f37c7d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
@@ -96,6 +96,8 @@
 import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.hideFromAccessibility
 import androidx.compose.ui.semantics.isTraversalGroup
 import androidx.compose.ui.semantics.role
 import androidx.compose.ui.semantics.semantics
@@ -461,15 +463,15 @@
             SubCategoryContainerDualPane(
                 searchQuery = searchQuery,
                 subCategory = subcategory,
-                isCustomizing = isCustomizing,
-                onCustomizationRequested = { label, subCategoryLabel ->
-                    onCustomizationRequested(
-                        ShortcutCustomizationRequestInfo.Add(
-                            label = label,
-                            subCategoryLabel = subCategoryLabel,
-                            categoryType = category.type,
-                        )
-                    )
+                isCustomizing = isCustomizing and category.type.includeInCustomization,
+                onCustomizationRequested = { requestInfo ->
+                    when (requestInfo) {
+                        is ShortcutCustomizationRequestInfo.Add ->
+                            onCustomizationRequested(requestInfo.copy(categoryType = category.type))
+
+                        is ShortcutCustomizationRequestInfo.Delete ->
+                            onCustomizationRequested(requestInfo.copy(categoryType = category.type))
+                    }
                 },
             )
             Spacer(modifier = Modifier.height(8.dp))
@@ -500,7 +502,7 @@
     searchQuery: String,
     subCategory: ShortcutSubCategory,
     isCustomizing: Boolean,
-    onCustomizationRequested: (String, String) -> Unit = { _: String, _: String -> },
+    onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit,
 ) {
     Surface(
         modifier = Modifier.fillMaxWidth(),
@@ -522,7 +524,19 @@
                     searchQuery = searchQuery,
                     shortcut = shortcut,
                     isCustomizing = isCustomizing,
-                    onCustomizationRequested = { onCustomizationRequested(it, subCategory.label) },
+                    onCustomizationRequested = { requestInfo ->
+                        when (requestInfo) {
+                            is ShortcutCustomizationRequestInfo.Add ->
+                                onCustomizationRequested(
+                                    requestInfo.copy(subCategoryLabel = subCategory.label)
+                                )
+
+                            is ShortcutCustomizationRequestInfo.Delete ->
+                                onCustomizationRequested(
+                                    requestInfo.copy(subCategoryLabel = subCategory.label)
+                                )
+                        }
+                    },
                 )
             }
         }
@@ -544,7 +558,7 @@
     searchQuery: String,
     shortcut: ShortcutModel,
     isCustomizing: Boolean = false,
-    onCustomizationRequested: (String) -> Unit = {},
+    onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
 ) {
     val interactionSource = remember { MutableInteractionSource() }
     val isFocused by interactionSource.collectIsFocusedAsState()
@@ -556,23 +570,43 @@
             }
             .focusable(interactionSource = interactionSource)
             .padding(8.dp)
+            .semantics { contentDescription = shortcut.contentDescription }
     ) {
         Row(
-            modifier = Modifier.width(128.dp).align(Alignment.CenterVertically).weight(0.333f),
+            modifier =
+                Modifier.width(128.dp).align(Alignment.CenterVertically).weight(0.333f).semantics {
+                    hideFromAccessibility()
+                },
             horizontalArrangement = Arrangement.spacedBy(16.dp),
             verticalAlignment = Alignment.CenterVertically,
         ) {
             if (shortcut.icon != null) {
-                ShortcutIcon(shortcut.icon, modifier = Modifier.size(24.dp))
+                ShortcutIcon(
+                    shortcut.icon,
+                    modifier = Modifier.size(24.dp).semantics { hideFromAccessibility() },
+                )
             }
-            ShortcutDescriptionText(searchQuery = searchQuery, shortcut = shortcut)
+            ShortcutDescriptionText(
+                searchQuery = searchQuery,
+                shortcut = shortcut,
+                modifier = Modifier.semantics { hideFromAccessibility() },
+            )
         }
-        Spacer(modifier = Modifier.width(24.dp))
+        Spacer(modifier = Modifier.width(24.dp).semantics { hideFromAccessibility() })
         ShortcutKeyCombinations(
-            modifier = Modifier.weight(.666f),
+            modifier = Modifier.weight(.666f).semantics { hideFromAccessibility() },
             shortcut = shortcut,
             isCustomizing = isCustomizing,
-            onAddShortcutRequested = { onCustomizationRequested(shortcut.label) },
+            onAddShortcutRequested = {
+                onCustomizationRequested(
+                    ShortcutCustomizationRequestInfo.Add(label = shortcut.label)
+                )
+            },
+            onDeleteShortcutRequested = {
+                onCustomizationRequested(
+                    ShortcutCustomizationRequestInfo.Delete(label = shortcut.label)
+                )
+            },
         )
     }
 }
@@ -761,7 +795,7 @@
     Text(
         modifier = modifier,
         text = textWithHighlightedSearchQuery(shortcut.label, searchQuery),
-        style = MaterialTheme.typography.bodyMedium,
+        style = MaterialTheme.typography.titleSmall,
         color = MaterialTheme.colorScheme.onSurface,
     )
 }
@@ -879,7 +913,7 @@
                 Text(
                     fontSize = 18.sp,
                     color = colors.textColor(selected).value,
-                    style = MaterialTheme.typography.headlineSmall,
+                    style = MaterialTheme.typography.titleSmall,
                     text = label,
                 )
             }
@@ -975,9 +1009,11 @@
     ) {
         Row(verticalAlignment = Alignment.CenterVertically) {
             Text(
-                stringResource(id = R.string.shortcut_helper_keyboard_settings_buttons_label),
+                text =
+                    stringResource(id = R.string.shortcut_helper_keyboard_settings_buttons_label),
                 color = MaterialTheme.colorScheme.onSurfaceVariant,
                 fontSize = 16.sp,
+                style = MaterialTheme.typography.titleSmall,
             )
             Spacer(modifier = Modifier.weight(1f))
             Icon(
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt
index 552c53d..990257d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt
@@ -21,11 +21,13 @@
 sealed interface ShortcutCustomizationUiState {
     data class AddShortcutDialog(
         val shortcutLabel: String,
-        val shouldShowErrorMessage: Boolean,
+        val errorMessage: String = "",
         val defaultCustomShortcutModifierKey: ShortcutKey.Icon.ResIdIcon,
         val isDialogShowing: Boolean,
         val pressedKeys: List<ShortcutKey> = emptyList(),
     ) : ShortcutCustomizationUiState
 
+    data class DeleteShortcutDialog(val isDialogShowing: Boolean) : ShortcutCustomizationUiState
+
     data object Inactive : ShortcutCustomizationUiState
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
index 2455ce4..b467bb4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.keyboard.shortcut.ui.viewmodel
 
-import androidx.compose.runtime.mutableStateOf
+import android.content.Context
 import androidx.compose.ui.input.key.Key
 import androidx.compose.ui.input.key.KeyEvent
 import androidx.compose.ui.input.key.KeyEventType
@@ -24,10 +24,14 @@
 import androidx.compose.ui.input.key.key
 import androidx.compose.ui.input.key.nativeKeyCode
 import androidx.compose.ui.input.key.type
+import com.android.systemui.keyboard.shared.model.ShortcutCustomizationRequestResult
 import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutCustomizationInteractor
 import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
 import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState
+import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState.AddShortcutDialog
+import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState.DeleteShortcutDialog
+import com.android.systemui.res.R
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -37,9 +41,10 @@
 
 class ShortcutCustomizationViewModel
 @AssistedInject
-constructor(private val shortcutCustomizationInteractor: ShortcutCustomizationInteractor) {
-    private val _shortcutBeingCustomized = mutableStateOf<ShortcutCustomizationRequestInfo?>(null)
-
+constructor(
+    private val context: Context,
+    private val shortcutCustomizationInteractor: ShortcutCustomizationInteractor,
+) {
     private val _shortcutCustomizationUiState =
         MutableStateFlow<ShortcutCustomizationUiState>(ShortcutCustomizationUiState.Inactive)
 
@@ -52,7 +57,7 @@
                 }
             }
             .combine(_shortcutCustomizationUiState) { keys, uiState ->
-                if (uiState is ShortcutCustomizationUiState.AddShortcutDialog) {
+                if (uiState is AddShortcutDialog) {
                     uiState.copy(pressedKeys = keys)
                 } else {
                     uiState
@@ -63,30 +68,34 @@
         when (requestInfo) {
             is ShortcutCustomizationRequestInfo.Add -> {
                 _shortcutCustomizationUiState.value =
-                    ShortcutCustomizationUiState.AddShortcutDialog(
+                    AddShortcutDialog(
                         shortcutLabel = requestInfo.label,
-                        shouldShowErrorMessage = false,
                         defaultCustomShortcutModifierKey =
                             shortcutCustomizationInteractor.getDefaultCustomShortcutModifierKey(),
                         isDialogShowing = false,
                         pressedKeys = emptyList(),
                     )
-                _shortcutBeingCustomized.value = requestInfo
+                shortcutCustomizationInteractor.onCustomizationRequested(requestInfo)
+            }
+
+            is ShortcutCustomizationRequestInfo.Delete -> {
+                _shortcutCustomizationUiState.value = DeleteShortcutDialog(isDialogShowing = false)
+                shortcutCustomizationInteractor.onCustomizationRequested(requestInfo)
             }
         }
     }
 
-    fun onAddShortcutDialogShown() {
+    fun onDialogShown() {
         _shortcutCustomizationUiState.update { uiState ->
-            (uiState as? ShortcutCustomizationUiState.AddShortcutDialog)?.copy(
-                isDialogShowing = true
-            ) ?: uiState
+            (uiState as? AddShortcutDialog)?.copy(isDialogShowing = true)
+                ?: (uiState as? DeleteShortcutDialog)?.copy(isDialogShowing = true)
+                ?: uiState
         }
     }
 
     fun onDialogDismissed() {
-        _shortcutBeingCustomized.value = null
         _shortcutCustomizationUiState.value = ShortcutCustomizationUiState.Inactive
+        shortcutCustomizationInteractor.onCustomizationRequested(null)
         shortcutCustomizationInteractor.updateUserSelectedKeyCombination(null)
     }
 
@@ -98,6 +107,51 @@
         return false
     }
 
+    suspend fun onSetShortcut() {
+        val result = shortcutCustomizationInteractor.confirmAndSetShortcutCurrentlyBeingCustomized()
+
+        _shortcutCustomizationUiState.update { uiState ->
+            when (result) {
+                ShortcutCustomizationRequestResult.SUCCESS -> ShortcutCustomizationUiState.Inactive
+                ShortcutCustomizationRequestResult.ERROR_RESERVED_COMBINATION -> {
+                    getUiStateWithErrorMessage(
+                        uiState = uiState,
+                        errorMessage =
+                            context.getString(
+                                R.string.shortcut_customizer_key_combination_in_use_error_message
+                            ),
+                    )
+                }
+
+                ShortcutCustomizationRequestResult.ERROR_OTHER ->
+                    getUiStateWithErrorMessage(
+                        uiState = uiState,
+                        errorMessage =
+                            context.getString(R.string.shortcut_customizer_generic_error_message),
+                    )
+            }
+        }
+    }
+
+    suspend fun deleteShortcutCurrentlyBeingCustomized() {
+        val result =
+            shortcutCustomizationInteractor.deleteShortcutCurrentlyBeingCustomized()
+
+        _shortcutCustomizationUiState.update { uiState ->
+            when (result) {
+                ShortcutCustomizationRequestResult.SUCCESS -> ShortcutCustomizationUiState.Inactive
+                else -> uiState
+            }
+        }
+    }
+
+    private fun getUiStateWithErrorMessage(
+        uiState: ShortcutCustomizationUiState,
+        errorMessage: String,
+    ): ShortcutCustomizationUiState {
+        return (uiState as? AddShortcutDialog)?.copy(errorMessage = errorMessage) ?: uiState
+    }
+
     private fun updatePressedKeys(keyEvent: KeyEvent) {
         val isModifier = SUPPORTED_MODIFIERS.contains(keyEvent.key)
         val keyCombination =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
index a94df09..7a72732 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
 import com.android.systemui.keyguard.ui.preview.KeyguardRemotePreviewManager
+import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
 import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
@@ -44,6 +45,7 @@
     ContentProvider(), SystemUIAppComponentFactoryBase.ContextInitializer {
 
     @Inject lateinit var interactor: KeyguardQuickAffordanceInteractor
+    @Inject lateinit var shadeModeInteractor: ShadeModeInteractor
     @Inject lateinit var previewManager: KeyguardRemotePreviewManager
     @Inject @Main lateinit var mainDispatcher: CoroutineDispatcher
 
@@ -73,6 +75,11 @@
                 MATCH_CODE_ALL_SELECTIONS,
             )
             addURI(Contract.AUTHORITY, Contract.FlagsTable.TABLE_NAME, MATCH_CODE_ALL_FLAGS)
+            addURI(
+                Contract.AUTHORITY,
+                Contract.RuntimeValuesTable.TABLE_NAME,
+                MATCH_CODE_ALL_RUNTIME_VALUES,
+            )
         }
 
     override fun onCreate(): Boolean {
@@ -94,7 +101,8 @@
                 MATCH_CODE_ALL_SLOTS,
                 MATCH_CODE_ALL_AFFORDANCES,
                 MATCH_CODE_ALL_FLAGS,
-                MATCH_CODE_ALL_SELECTIONS -> "vnd.android.cursor.dir/vnd."
+                MATCH_CODE_ALL_SELECTIONS,
+                MATCH_CODE_ALL_RUNTIME_VALUES -> "vnd.android.cursor.dir/vnd."
                 else -> null
             }
 
@@ -113,6 +121,7 @@
                         Contract.LockScreenQuickAffordances.SelectionTable.TABLE_NAME
                     )
                 MATCH_CODE_ALL_FLAGS -> Contract.FlagsTable.TABLE_NAME
+                MATCH_CODE_ALL_RUNTIME_VALUES -> Contract.RuntimeValuesTable.TABLE_NAME
                 else -> null
             }
 
@@ -146,6 +155,7 @@
                 MATCH_CODE_ALL_SLOTS -> querySlots()
                 MATCH_CODE_ALL_SELECTIONS -> querySelections()
                 MATCH_CODE_ALL_FLAGS -> queryFlags()
+                MATCH_CODE_ALL_RUNTIME_VALUES -> queryRuntimeValues()
                 else -> null
             }
         }
@@ -334,6 +344,23 @@
             }
     }
 
+    private fun queryRuntimeValues(): Cursor {
+        return MatrixCursor(
+                arrayOf(
+                    Contract.RuntimeValuesTable.Columns.NAME,
+                    Contract.RuntimeValuesTable.Columns.VALUE,
+                )
+            )
+            .apply {
+                addRow(
+                    arrayOf(
+                        Contract.RuntimeValuesTable.KEY_IS_SHADE_LAYOUT_WIDE,
+                        if (shadeModeInteractor.isShadeLayoutWide.value) 1 else 0,
+                    )
+                )
+            }
+    }
+
     private suspend fun deleteSelection(uri: Uri, selectionArgs: Array<out String>?): Int {
         if (selectionArgs == null) {
             throw IllegalArgumentException(
@@ -370,5 +397,6 @@
         private const val MATCH_CODE_ALL_AFFORDANCES = 2
         private const val MATCH_CODE_ALL_SELECTIONS = 3
         private const val MATCH_CODE_ALL_FLAGS = 4
+        private const val MATCH_CODE_ALL_RUNTIME_VALUES = 5
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 7097c1d..d40fe46 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -81,7 +81,7 @@
 import com.android.systemui.keyguard.domain.interactor.KeyguardDismissInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardEnabledInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
-import com.android.systemui.keyguard.domain.interactor.KeyguardLockWhileAwakeInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardServiceLockNowInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardStateCallbackInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardWakeDirectlyToGoneInteractor;
 import com.android.systemui.keyguard.ui.binder.KeyguardSurfaceBehindParamsApplier;
@@ -330,8 +330,7 @@
             return new FoldGracePeriodProvider();
         }
     };
-    private final KeyguardLockWhileAwakeInteractor
-            mKeyguardLockWhileAwakeInteractor;
+    private final KeyguardServiceLockNowInteractor mKeyguardServiceLockNowInteractor;
 
     @Inject
     public KeyguardService(
@@ -357,7 +356,7 @@
             KeyguardDismissInteractor keyguardDismissInteractor,
             Lazy<DeviceEntryInteractor> deviceEntryInteractorLazy,
             KeyguardStateCallbackInteractor keyguardStateCallbackInteractor,
-            KeyguardLockWhileAwakeInteractor keyguardLockWhileAwakeInteractor) {
+            KeyguardServiceLockNowInteractor keyguardServiceLockNowInteractor) {
         super();
         mKeyguardViewMediator = keyguardViewMediator;
         mKeyguardLifecyclesDispatcher = keyguardLifecyclesDispatcher;
@@ -389,7 +388,7 @@
         mKeyguardEnabledInteractor = keyguardEnabledInteractor;
         mKeyguardWakeDirectlyToGoneInteractor = keyguardWakeDirectlyToGoneInteractor;
         mKeyguardDismissInteractor = keyguardDismissInteractor;
-        mKeyguardLockWhileAwakeInteractor = keyguardLockWhileAwakeInteractor;
+        mKeyguardServiceLockNowInteractor = keyguardServiceLockNowInteractor;
     }
 
     @Override
@@ -665,7 +664,7 @@
             if (SceneContainerFlag.isEnabled()) {
                 mDeviceEntryInteractorLazy.get().lockNow();
             } else if (KeyguardWmStateRefactor.isEnabled()) {
-                mKeyguardLockWhileAwakeInteractor.onKeyguardServiceDoKeyguardTimeout(options);
+                mKeyguardServiceLockNowInteractor.onKeyguardServiceDoKeyguardTimeout(options);
             }
 
             mKeyguardViewMediator.doKeyguardTimeout(options);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 01ec4d0..9f13160 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -3943,7 +3943,7 @@
     }
 
     private void notifyDefaultDisplayCallbacks(boolean showing) {
-        if (SceneContainerFlag.isEnabled()) {
+        if (SceneContainerFlag.isEnabled() || KeyguardWmStateRefactor.isEnabled()) {
             return;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt
index 0b78be1..8906156 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt
@@ -25,6 +25,7 @@
 import com.android.systemui.communal.data.repository.CommunalSceneRepository
 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.res.R
@@ -98,7 +99,10 @@
         if (SceneContainerFlag.isEnabled) {
             sceneInteractor.changeScene(Scenes.Communal, "lockscreen to communal from shortcut")
         } else {
-            communalSceneRepository.changeScene(CommunalScenes.Communal, null)
+            communalSceneRepository.changeScene(
+                CommunalScenes.Communal,
+                transitionKey = CommunalTransitionKeys.SimpleFade,
+            )
         }
         return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 1e672e2..deef2a6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -21,11 +21,13 @@
 import android.app.DreamManager
 import com.android.app.animation.Interpolators
 import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.systemui.Flags.communalHubOnMobile
 import com.android.systemui.Flags.communalSceneKtfRefactor
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
 import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
 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.Background
 import com.android.systemui.dagger.qualifiers.Main
@@ -48,7 +50,6 @@
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.debounce
 import kotlinx.coroutines.flow.filter
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SysUISingleton
@@ -176,6 +177,9 @@
                         communalSceneInteractor.changeScene(
                             newScene = CommunalScenes.Communal,
                             loggingReason = "FromDreamingTransitionInteractor",
+                            transitionKey =
+                                if (communalHubOnMobile()) CommunalTransitionKeys.SimpleFade
+                                else null,
                         )
                     } else {
                         startTransitionTo(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
index 21090c1..cc8652c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
@@ -18,7 +18,6 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import com.android.keyguard.logging.KeyguardLogger
-import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlags
 import com.android.systemui.dagger.SysUISingleton
@@ -28,15 +27,12 @@
 import com.android.systemui.keyguard.shared.model.DismissAction
 import com.android.systemui.keyguard.shared.model.KeyguardDone
 import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
-import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
 import com.android.systemui.lifecycle.ExclusiveActivatable
 import com.android.systemui.log.core.LogLevel
-import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
-import com.android.systemui.util.kotlin.Utils.Companion.sampleFilter
 import dagger.Lazy
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -66,8 +62,6 @@
     val dismissInteractor: KeyguardDismissInteractor,
     @Application private val applicationScope: CoroutineScope,
     deviceUnlockedInteractor: Lazy<DeviceUnlockedInteractor>,
-    powerInteractor: PowerInteractor,
-    alternateBouncerInteractor: AlternateBouncerInteractor,
     shadeInteractor: Lazy<ShadeInteractor>,
     keyguardInteractor: Lazy<KeyguardInteractor>,
     sceneInteractor: Lazy<SceneInteractor>,
@@ -144,42 +138,6 @@
             }
         }
 
-    /** Flow that emits whenever we need to reset the dismiss action */
-    private val resetDismissAction: Flow<Unit> =
-        combine(
-                if (SceneContainerFlag.isEnabled) {
-                    // Using currentScene instead of isFinishedIn because of a race condition that
-                    // forms between isFinishedIn(Gone) and isOnShadeWhileUnlocked where the latter
-                    // emits false before the former emits true, causing the evaluation of the
-                    // combine to come up with true, temporarily, before settling on false, which is
-                    // a valid final state. That causes an incorrect reset of the dismiss action to
-                    // occur before it gets executed.
-                    sceneInteractor
-                        .get()
-                        .currentScene
-                        .map { it == Scenes.Gone }
-                        .distinctUntilChanged()
-                } else {
-                    transitionInteractor.isFinishedIn(
-                        scene = Scenes.Gone,
-                        stateWithoutSceneContainer = GONE,
-                    )
-                },
-                transitionInteractor.isFinishedIn(
-                    scene = Scenes.Bouncer,
-                    stateWithoutSceneContainer = PRIMARY_BOUNCER,
-                ),
-                alternateBouncerInteractor.isVisible,
-                isOnShadeWhileUnlocked,
-                powerInteractor.isAsleep,
-            ) { isOnGone, isOnBouncer, isOnAltBouncer, isOnShadeWhileUnlocked, isAsleep ->
-                (!isOnGone && !isOnBouncer && !isOnAltBouncer && !isOnShadeWhileUnlocked) ||
-                    isAsleep
-            }
-            .filter { it }
-            .sampleFilter(dismissAction) { it !is DismissAction.None }
-            .map {}
-
     fun runDismissAnimationOnKeyguard(): Boolean {
         return willAnimateDismissActionOnLockscreen.value
     }
@@ -220,19 +178,15 @@
                 }
             }
 
-            launch {
-                resetDismissAction.collect {
-                    log("resetDismissAction")
-                    repository.dismissAction.value.onCancelAction.run()
-                    clearDismissAction()
-                }
-            }
-
             launch { repository.dismissAction.collect { log("updatedDismissAction=$it") } }
             awaitCancellation()
         }
     }
 
+    fun clearDismissAction() {
+        repository.setDismissAction(DismissAction.None)
+    }
+
     /** Run the dismiss action and starts the dismiss keyguard transition. */
     private suspend fun runDismissAction() {
         val dismissAction = repository.dismissAction.value
@@ -249,10 +203,6 @@
         }
     }
 
-    private fun clearDismissAction() {
-        repository.setDismissAction(DismissAction.None)
-    }
-
     private fun log(message: String) {
         keyguardLogger.log(TAG, LogLevel.DEBUG, message)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt
index 631e44a..42cbd7d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt
@@ -16,39 +16,52 @@
 
 package com.android.systemui.keyguard.domain.interactor
 
+import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.KeyguardRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import com.android.systemui.util.kotlin.sample
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
-import com.android.app.tracing.coroutines.launchTraced as launch
+import kotlinx.coroutines.withContext
 
 /**
- * Logic around the keyguard being enabled/disabled, per [KeyguardService]. If the keyguard is not
- * enabled, the lockscreen cannot be shown and the device will go from AOD/DOZING directly to GONE.
+ * Logic around the keyguard being enabled, disabled, or suppressed via adb. If the keyguard is
+ * disabled or suppressed, the lockscreen cannot be shown and the device will go from AOD/DOZING
+ * directly to GONE.
  *
  * Keyguard can be disabled by selecting Security: "None" in settings, or by apps that hold
  * permission to do so (such as Phone). Some CTS tests also disable keyguard in onCreate or onStart
  * rather than simply dismissing the keyguard or setting up the device to have Security: None, for
  * reasons unknown.
+ *
+ * Keyguard can be suppressed by calling "adb shell locksettings set-disabled true", which is
+ * frequently done in tests. If keyguard is suppressed, it won't show even if the keyguard is
+ * enabled. If keyguard is not suppressed, then we defer to whether keyguard is enabled or disabled.
  */
 @SysUISingleton
 class KeyguardEnabledInteractor
 @Inject
 constructor(
-    @Application scope: CoroutineScope,
+    @Application val scope: CoroutineScope,
+    @Background val backgroundDispatcher: CoroutineDispatcher,
     val repository: KeyguardRepository,
     val biometricSettingsRepository: BiometricSettingsRepository,
-    keyguardDismissTransitionInteractor: KeyguardDismissTransitionInteractor,
+    private val selectedUserInteractor: SelectedUserInteractor,
+    private val lockPatternUtils: LockPatternUtils,
+    keyguardDismissTransitionInteractor: dagger.Lazy<KeyguardDismissTransitionInteractor>,
     internalTransitionInteractor: InternalKeyguardTransitionInteractor,
 ) {
 
@@ -62,6 +75,10 @@
      * If the keyguard is disabled while we're locked, we will transition to GONE unless we're in
      * lockdown mode. If the keyguard is re-enabled, we'll transition back to LOCKSCREEN if we were
      * locked when it was disabled.
+     *
+     * Even if the keyguard is enabled, it's possible for it to be suppressed temporarily via adb.
+     * If you need to respect that adb command, you will need to use
+     * [isKeyguardEnabledAndNotSuppressed] instead of using this flow.
      */
     val isKeyguardEnabled: StateFlow<Boolean> = repository.isKeyguardEnabled
 
@@ -96,9 +113,9 @@
                         val currentTransitionInfo =
                             internalTransitionInteractor.currentTransitionInfoInternal()
                         if (currentTransitionInfo.to != KeyguardState.GONE && !inLockdown) {
-                            keyguardDismissTransitionInteractor.startDismissKeyguardTransition(
-                                "keyguard disabled"
-                            )
+                            keyguardDismissTransitionInteractor
+                                .get()
+                                .startDismissKeyguardTransition("keyguard disabled")
                         }
                     }
             }
@@ -116,4 +133,37 @@
     fun isShowKeyguardWhenReenabled(): Boolean {
         return repository.isShowKeyguardWhenReenabled()
     }
+
+    /**
+     * Whether the keyguard is enabled, and has not been suppressed via adb.
+     *
+     * There is unfortunately no callback for [isKeyguardSuppressed], which means this can't be a
+     * flow, since it's ambiguous when we would query the latest suppression value.
+     */
+    suspend fun isKeyguardEnabledAndNotSuppressed(): Boolean {
+        return isKeyguardEnabled.value && !isKeyguardSuppressed()
+    }
+
+    /**
+     * Returns whether the lockscreen has been disabled ("suppressed") via "adb shell locksettings
+     * set-disabled". If suppressed, we'll ignore all signals that would typically result in showing
+     * the keyguard, regardless of the value of [isKeyguardEnabled].
+     *
+     * It's extremely confusing to have [isKeyguardEnabled] not be the inverse of "is lockscreen
+     * disabled", so this method intentionally re-terms it as "suppressed".
+     *
+     * Note that if the lockscreen is currently showing when it's suppressed, it will remain visible
+     * until it's unlocked, at which point it will never re-appear until suppression is removed.
+     */
+    suspend fun isKeyguardSuppressed(
+        userId: Int = selectedUserInteractor.getSelectedUserId()
+    ): Boolean {
+        // isLockScreenDisabled returns true whenever keyguard is not enabled, even if the adb
+        // command was not used to disable/suppress the lockscreen. To make these booleans as clear
+        // as possible, only return true if keyguard is suppressed when it otherwise would have
+        // been enabled.
+        return withContext(backgroundDispatcher) {
+            isKeyguardEnabled.value && lockPatternUtils.isLockScreenDisabled(userId)
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLockWhileAwakeInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLockWhileAwakeInteractor.kt
index 0ab3e5c..ce84e71 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLockWhileAwakeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLockWhileAwakeInteractor.kt
@@ -16,27 +16,16 @@
 
 package com.android.systemui.keyguard.domain.interactor
 
-import android.os.Bundle
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
 import com.android.systemui.util.kotlin.sample
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.merge
 
-/**
- * Emitted when we receive a [KeyguardLockWhileAwakeInteractor.onKeyguardServiceDoKeyguardTimeout]
- * call.
- *
- * Includes a timestamp so it's not conflated by the StateFlow.
- */
-data class KeyguardTimeoutWhileAwakeEvent(val timestamp: Long, val options: Bundle?)
-
 /** The reason we're locking while awake, used for logging. */
 enum class LockWhileAwakeReason(private val logReason: String) {
     LOCKDOWN("Lockdown initiated."),
@@ -71,10 +60,8 @@
 constructor(
     biometricSettingsRepository: BiometricSettingsRepository,
     keyguardEnabledInteractor: KeyguardEnabledInteractor,
+    keyguardServiceLockNowInteractor: KeyguardServiceLockNowInteractor,
 ) {
-    /** Emits whenever a timeout event is received by [KeyguardService]. */
-    private val timeoutEvents: MutableStateFlow<KeyguardTimeoutWhileAwakeEvent?> =
-        MutableStateFlow(null)
 
     /** Emits whenever the current user is in lockdown mode. */
     private val inLockdown: Flow<LockWhileAwakeReason> =
@@ -97,25 +84,19 @@
     /** Emits whenever we should lock while the screen is on, for any reason. */
     val lockWhileAwakeEvents: Flow<LockWhileAwakeReason> =
         merge(
-            inLockdown,
-            keyguardReenabled,
-            timeoutEvents.filterNotNull().map {
-                LockWhileAwakeReason.KEYGUARD_TIMEOUT_WHILE_SCREEN_ON
-            },
+            // We're in lockdown, and the keyguard is enabled. If the keyguard is disabled, the
+            // lockdown button is hidden in the UI, but it's still possible to trigger lockdown in
+            // tests.
+            inLockdown
+                .filter { keyguardEnabledInteractor.isKeyguardEnabledAndNotSuppressed() }
+                .map { LockWhileAwakeReason.LOCKDOWN },
+            // The keyguard was re-enabled, and it was showing when it was originally disabled.
+            // Tests currently expect that if the keyguard is re-enabled, it will show even if it's
+            // suppressed, so we don't check for isKeyguardEnabledAndNotSuppressed() on this flow.
+            keyguardReenabled.map { LockWhileAwakeReason.KEYGUARD_REENABLED },
+            // KeyguardService says we need to lock now, and the lockscreen is enabled.
+            keyguardServiceLockNowInteractor.lockNowEvents
+                .filter { keyguardEnabledInteractor.isKeyguardEnabledAndNotSuppressed() }
+                .map { LockWhileAwakeReason.KEYGUARD_TIMEOUT_WHILE_SCREEN_ON },
         )
-
-    /**
-     * Called by [KeyguardService] when it receives a doKeyguardTimeout() call. This indicates that
-     * the device locked while the screen was on.
-     *
-     * [options] appears to be no longer used, but we'll keep it in this interactor in case that
-     * turns out not to be true.
-     */
-    fun onKeyguardServiceDoKeyguardTimeout(options: Bundle?) {
-        timeoutEvents.value =
-            KeyguardTimeoutWhileAwakeEvent(
-                timestamp = System.currentTimeMillis(),
-                options = options,
-            )
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardServiceLockNowInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardServiceLockNowInteractor.kt
new file mode 100644
index 0000000..9ed53ea
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardServiceLockNowInteractor.kt
@@ -0,0 +1,73 @@
+/*
+ * 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 android.annotation.SuppressLint
+import android.os.Bundle
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.launch
+
+/**
+ * Emitted when we receive a [KeyguardServiceLockNowInteractor.onKeyguardServiceDoKeyguardTimeout]
+ * call.
+ */
+data class KeyguardLockNowEvent(val options: Bundle?)
+
+/**
+ * Logic around requests by [KeyguardService] to lock the device right now, even though the device
+ * is awake and not going to sleep.
+ *
+ * This can happen if WM#lockNow() is called, or if the screen is forced to stay awake but the lock
+ * timeout elapses.
+ *
+ * This is not the only way for the device to lock while the screen is on. The other cases, which do
+ * not directly involve [KeyguardService], are handled in [KeyguardLockWhileAwakeInteractor].
+ */
+@SysUISingleton
+class KeyguardServiceLockNowInteractor
+@Inject
+constructor(@Background val backgroundScope: CoroutineScope) {
+
+    /**
+     * Emits whenever [KeyguardService] receives a call that indicates we should lock the device
+     * right now, even though the device is awake and not going to sleep.
+     *
+     * WARNING: This is only one of multiple reasons the device might need to lock while not going
+     * to sleep. Unless you're dealing with keyguard internals that specifically need to know that
+     * we're locking due to a call to doKeyguardTimeout, use
+     * [KeyguardLockWhileAwakeInteractor.lockWhileAwakeEvents].
+     *
+     * This is fundamentally an event flow, hence the SharedFlow.
+     */
+    @SuppressLint("SharedFlowCreation")
+    val lockNowEvents: MutableSharedFlow<KeyguardLockNowEvent> = MutableSharedFlow()
+
+    /**
+     * Called by [KeyguardService] when it receives a doKeyguardTimeout() call. This indicates that
+     * the device locked while the screen was on.
+     *
+     * [options] appears to be no longer used, but we'll keep it in this interactor in case that
+     * turns out not to be true.
+     */
+    fun onKeyguardServiceDoKeyguardTimeout(options: Bundle?) {
+        backgroundScope.launch { lockNowEvents.emit(KeyguardLockNowEvent(options = options)) }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt
index fbc7e2a..8641dfa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt
@@ -25,6 +25,7 @@
 import android.content.IntentFilter
 import android.provider.Settings
 import android.provider.Settings.Secure
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
@@ -48,20 +49,21 @@
 import kotlin.math.max
 import kotlin.math.min
 import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.distinctUntilChangedBy
 import kotlinx.coroutines.flow.map
-import com.android.app.tracing.coroutines.launchTraced as launch
+import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.onStart
 
 /**
  * Logic related to the ability to wake directly to GONE from asleep (AOD/DOZING), without going
  * through LOCKSCREEN or a BOUNCER state.
  *
  * This is possible in the following scenarios:
- * - The lockscreen is disabled, either from an app request (SUW does this), or by the security
+ * - The keyguard is not enabled, either from an app request (SUW does this), or by the security
  *   "None" setting.
+ * - The keyguard was suppressed via adb.
  * - A biometric authentication event occurred while we were asleep (fingerprint auth, etc). This
  *   specifically is referred to throughout the codebase as "wake and unlock".
  * - The screen timed out, but the "lock after screen timeout" duration has not elapsed.
@@ -86,43 +88,44 @@
     private val lockPatternUtils: LockPatternUtils,
     private val systemSettings: SystemSettings,
     private val selectedUserInteractor: SelectedUserInteractor,
+    keyguardEnabledInteractor: KeyguardEnabledInteractor,
+    keyguardServiceLockNowInteractor: KeyguardServiceLockNowInteractor,
 ) {
 
     /**
-     * Whether the lockscreen was disabled as of the last wake/sleep event, according to
-     * LockPatternUtils.
-     *
-     * This will always be true if [repository.isKeyguardServiceEnabled]=false, but it can also be
-     * true when the keyguard service is enabled if the lockscreen has been disabled via adb using
-     * the `adb shell locksettings set-disabled true` command, which is often done in tests.
-     *
-     * Unlike keyguardServiceEnabled, changes to this value should *not* immediately show or hide
-     * the keyguard. If the lockscreen is disabled in this way, it will just not show on the next
-     * sleep/wake.
+     * Whether the keyguard was suppressed as of the most recent wakefulness event or lockNow
+     * command. Keyguard suppression can only be queried (there is no callback available), and
+     * legacy code only queried the value in onStartedGoingToSleep and doKeyguardTimeout. Tests now
+     * depend on that behavior, so for now, we'll replicate it here.
      */
-    private val isLockscreenDisabled: Flow<Boolean> =
-        powerInteractor.isAwake.map { isLockscreenDisabled() }
+    private val shouldSuppressKeyguard =
+        merge(powerInteractor.isAwake, keyguardServiceLockNowInteractor.lockNowEvents)
+            .map { keyguardEnabledInteractor.isKeyguardSuppressed() }
+            // Default to false, so that flows that combine this one emit prior to the first
+            // wakefulness emission.
+            .onStart { emit(false) }
 
     /**
      * Whether we can wake from AOD/DOZING directly to GONE, bypassing LOCKSCREEN/BOUNCER states.
      *
      * This is possible in the following cases:
      * - Keyguard is disabled, either from an app request or from security being set to "None".
+     * - Keyguard is suppressed, via adb locksettings.
      * - We're wake and unlocking (fingerprint auth occurred while asleep).
      * - We're allowed to ignore auth and return to GONE, due to timeouts not elapsing.
      */
     val canWakeDirectlyToGone =
         combine(
                 repository.isKeyguardEnabled,
-                isLockscreenDisabled,
+                shouldSuppressKeyguard,
                 repository.biometricUnlockState,
                 repository.canIgnoreAuthAndReturnToGone,
             ) {
                 keyguardEnabled,
-                isLockscreenDisabled,
+                shouldSuppressKeyguard,
                 biometricUnlockState,
                 canIgnoreAuthAndReturnToGone ->
-                (!keyguardEnabled || isLockscreenDisabled) ||
+                (!keyguardEnabled || shouldSuppressKeyguard) ||
                     BiometricUnlockMode.isWakeAndUnlock(biometricUnlockState.mode) ||
                     canIgnoreAuthAndReturnToGone
             }
@@ -186,9 +189,9 @@
                 .sample(
                     transitionInteractor.isCurrentlyIn(
                         Scenes.Gone,
-                        stateWithoutSceneContainer = KeyguardState.GONE
+                        stateWithoutSceneContainer = KeyguardState.GONE,
                     ),
-                    ::Pair
+                    ::Pair,
                 )
                 .collect { (wakefulness, finishedInGone) ->
                     // Save isAwake for use in onDreamingStarted/onDreamingStopped.
@@ -260,7 +263,7 @@
             delayedActionFilter,
             SYSTEMUI_PERMISSION,
             null /* scheduler */,
-            Context.RECEIVER_EXPORTED_UNAUDITED
+            Context.RECEIVER_EXPORTED_UNAUDITED,
         )
     }
 
@@ -282,7 +285,7 @@
                 context,
                 0,
                 intent,
-                PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
+                PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE,
             )
 
         val time = systemClock.elapsedRealtime() + getCanIgnoreAuthAndReturnToGoneDuration()
@@ -311,16 +314,6 @@
     }
 
     /**
-     * Returns whether the lockscreen is disabled, either because the keyguard service is disabled
-     * or because an adb command has disabled the lockscreen.
-     */
-    private fun isLockscreenDisabled(
-        userId: Int = selectedUserInteractor.getSelectedUserId()
-    ): Boolean {
-        return lockPatternUtils.isLockScreenDisabled(userId)
-    }
-
-    /**
      * Returns the duration within which we can return to GONE without auth after a screen timeout
      * (or power button press, if lock instantly is disabled).
      *
@@ -336,7 +329,7 @@
                 .getIntForUser(
                     Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
                     KEYGUARD_CAN_IGNORE_AUTH_DURATION,
-                    userId
+                    userId,
                 )
                 .toLong()
 
@@ -352,7 +345,7 @@
                     .getIntForUser(
                         Settings.System.SCREEN_OFF_TIMEOUT,
                         KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT,
-                        userId
+                        userId,
                     )
                     .toLong()
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
index 364b1a9..9df293b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
@@ -112,8 +112,10 @@
             }
             .distinctUntilChanged()
 
-    private val isDeviceEntered by lazy { deviceEntryInteractor.get().isDeviceEntered }
-    private val isDeviceNotEntered by lazy { isDeviceEntered.map { !it } }
+    private val isDeviceEnteredDirectly by lazy {
+        deviceEntryInteractor.get().isDeviceEnteredDirectly
+    }
+    private val isDeviceNotEnteredDirectly by lazy { isDeviceEnteredDirectly.map { !it } }
 
     /**
      * Surface visibility, which is either determined by the default visibility when not
@@ -126,7 +128,7 @@
                 sceneInteractor.get().transitionState.flatMapLatestConflated { state ->
                     when {
                         state.isTransitioning(from = Scenes.Lockscreen, to = Scenes.Gone) ->
-                            isDeviceEntered
+                            isDeviceEnteredDirectly
                         state.isTransitioning(from = Scenes.Bouncer, to = Scenes.Gone) ->
                             (state as Transition).progress.map { progress ->
                                 progress >
@@ -210,7 +212,7 @@
                             when (it.currentScene) {
                                 in keyguardScenes -> flowOf(true)
                                 in nonKeyguardScenes -> flowOf(false)
-                                in keyguardAgnosticScenes -> isDeviceNotEntered
+                                in keyguardAgnosticScenes -> isDeviceNotEnteredDirectly
                                 else ->
                                     throw IllegalStateException("Unknown scene: ${it.currentScene}")
                             }
@@ -220,7 +222,7 @@
                                 it.isTransitioningSets(from = keyguardScenes) -> flowOf(true)
                                 it.isTransitioningSets(from = nonKeyguardScenes) -> flowOf(false)
                                 it.isTransitioningSets(from = keyguardAgnosticScenes) ->
-                                    isDeviceNotEntered
+                                    isDeviceNotEnteredDirectly
                                 else ->
                                     throw IllegalStateException("Unknown scene: ${it.fromContent}")
                             }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
index 6c03b24..ac302dd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
@@ -17,7 +17,7 @@
 
 package com.android.systemui.keyguard.ui.binder
 
-import android.content.Context
+import android.content.res.Resources
 import android.view.View
 import android.view.View.INVISIBLE
 import android.view.View.VISIBLE
@@ -34,8 +34,8 @@
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewClockViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.plugins.clocks.ClockPreviewConfig
 import com.android.systemui.shared.clocks.ClockRegistry
-import kotlin.reflect.KSuspendFunction1
 
 /** Binder for the small clock view, large clock view. */
 object KeyguardPreviewClockViewBinder {
@@ -66,11 +66,11 @@
 
     @JvmStatic
     fun bind(
-        context: Context,
         rootView: ConstraintLayout,
         viewModel: KeyguardPreviewClockViewModel,
         clockRegistry: ClockRegistry,
-        updateClockAppearance: KSuspendFunction1<ClockController, Unit>,
+        updateClockAppearance: suspend (ClockController, Resources) -> Unit,
+        clockPreviewConfig: ClockPreviewConfig,
     ) {
         rootView.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.STARTED) {
@@ -82,7 +82,10 @@
                                     .forEach { rootView.removeView(it) }
                             }
                             lastClock = currentClock
-                            updateClockAppearance(currentClock)
+                            updateClockAppearance(
+                                currentClock,
+                                clockPreviewConfig.previewContext.resources,
+                            )
 
                             if (viewModel.shouldHighlightSelectedAffordance) {
                                 (currentClock.largeClock.layout.views +
@@ -98,7 +101,12 @@
                                 (it.parent as? ViewGroup)?.removeView(it)
                                 rootView.addView(it)
                             }
-                            applyPreviewConstraints(context, rootView, currentClock, viewModel)
+                            applyPreviewConstraints(
+                                clockPreviewConfig,
+                                rootView,
+                                currentClock,
+                                viewModel,
+                            )
                         }
                     }
                     .invokeOnCompletion {
@@ -121,14 +129,14 @@
     }
 
     private fun applyPreviewConstraints(
-        context: Context,
+        clockPreviewConfig: ClockPreviewConfig,
         rootView: ConstraintLayout,
         previewClock: ClockController,
         viewModel: KeyguardPreviewClockViewModel,
     ) {
         val cs = ConstraintSet().apply { clone(rootView) }
-        previewClock.largeClock.layout.applyPreviewConstraints(context, cs)
-        previewClock.smallClock.layout.applyPreviewConstraints(context, cs)
+        previewClock.largeClock.layout.applyPreviewConstraints(clockPreviewConfig, cs)
+        previewClock.smallClock.layout.applyPreviewConstraints(clockPreviewConfig, cs)
 
         // When selectedClockSize is the initial value, make both clocks invisible to avoid
         // flickering
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 baa6812..e89be5d 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
@@ -17,7 +17,6 @@
 
 package com.android.systemui.keyguard.ui.binder
 
-import android.content.Context
 import android.view.View
 import androidx.core.view.isInvisible
 import androidx.lifecycle.Lifecycle
@@ -26,16 +25,16 @@
 import com.android.systemui.keyguard.shared.model.ClockSizeSetting
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewSmartspaceViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.plugins.clocks.ClockPreviewConfig
 
 /** Binder for the small clock view, large clock view and smartspace. */
 object KeyguardPreviewSmartspaceViewBinder {
 
     @JvmStatic
     fun bind(
-        previewContext: Context,
         smartspace: View,
-        splitShadePreview: Boolean,
         viewModel: KeyguardPreviewSmartspaceViewModel,
+        clockPreviewConfig: ClockPreviewConfig,
     ) {
         smartspace.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.STARTED) {
@@ -44,15 +43,9 @@
                         val topPadding =
                             when (it) {
                                 ClockSizeSetting.DYNAMIC ->
-                                    viewModel.getLargeClockSmartspaceTopPadding(
-                                        splitShadePreview,
-                                        previewContext,
-                                    )
+                                    viewModel.getLargeClockSmartspaceTopPadding(clockPreviewConfig)
                                 ClockSizeSetting.SMALL ->
-                                    viewModel.getSmallClockSmartspaceTopPadding(
-                                        splitShadePreview,
-                                        previewContext,
-                                    )
+                                    viewModel.getSmallClockSmartspaceTopPadding(clockPreviewConfig)
                             }
                         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 ab9cffc..9924a3b 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
@@ -22,6 +22,7 @@
 import android.content.Context
 import android.content.Intent
 import android.content.IntentFilter
+import android.content.res.Resources
 import android.graphics.Rect
 import android.hardware.display.DisplayManager
 import android.os.Bundle
@@ -47,6 +48,7 @@
 import androidx.constraintlayout.widget.ConstraintSet.START
 import androidx.constraintlayout.widget.ConstraintSet.TOP
 import androidx.core.view.isInvisible
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.internal.policy.SystemBarUtils
 import com.android.keyguard.ClockEventController
 import com.android.keyguard.KeyguardClockSwitch
@@ -57,6 +59,7 @@
 import com.android.systemui.communal.ui.binder.CommunalTutorialIndicatorViewBinder
 import com.android.systemui.communal.ui.viewmodel.CommunalTutorialIndicatorViewModel
 import com.android.systemui.coroutines.newTracingContext
+import com.android.systemui.customization.R as customR
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
@@ -80,9 +83,11 @@
 import com.android.systemui.monet.ColorScheme
 import com.android.systemui.monet.Style
 import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.plugins.clocks.ClockPreviewConfig
 import com.android.systemui.plugins.clocks.ThemeConfig
 import com.android.systemui.plugins.clocks.WeatherData
 import com.android.systemui.res.R
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.shared.clocks.ClockRegistry
 import com.android.systemui.shared.clocks.DefaultClockController
@@ -105,7 +110,6 @@
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.cancel
 import kotlinx.coroutines.flow.flowOf
-import com.android.app.tracing.coroutines.launchTraced as launch
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
 import org.json.JSONException
@@ -352,8 +356,11 @@
 
         val topPadding: Int =
             smartspaceViewModel.getLargeClockSmartspaceTopPadding(
-                previewInSplitShade(),
-                previewContext,
+                ClockPreviewConfig(
+                    previewContext,
+                    getPreviewShadeLayoutWide(display!!),
+                    SceneContainerFlag.isEnabled,
+                )
             )
         val startPadding: Int = smartspaceViewModel.getSmartspaceStartPadding(previewContext)
         val endPadding: Int = smartspaceViewModel.getSmartspaceEndPadding(previewContext)
@@ -436,11 +443,15 @@
             setUpClock(previewContext, rootView)
             if (MigrateClocksToBlueprint.isEnabled) {
                 KeyguardPreviewClockViewBinder.bind(
-                    previewContext,
                     keyguardRootView,
                     clockViewModel,
                     clockRegistry,
                     ::updateClockAppearance,
+                    ClockPreviewConfig(
+                        previewContext,
+                        getPreviewShadeLayoutWide(display!!),
+                        SceneContainerFlag.isEnabled,
+                    ),
                 )
             } else {
                 KeyguardPreviewClockViewBinder.bind(
@@ -455,10 +466,14 @@
 
         smartSpaceView?.let {
             KeyguardPreviewSmartspaceViewBinder.bind(
-                previewContext,
                 it,
-                previewInSplitShade(),
                 smartspaceViewModel,
+                clockPreviewConfig =
+                    ClockPreviewConfig(
+                        previewContext,
+                        getPreviewShadeLayoutWide(display!!),
+                        SceneContainerFlag.isEnabled,
+                    ),
             )
         }
         setupCommunalTutorialIndicator(keyguardRootView)
@@ -552,20 +567,14 @@
             val layoutParams =
                 FrameLayout.LayoutParams(
                     FrameLayout.LayoutParams.WRAP_CONTENT,
-                    resources.getDimensionPixelSize(
-                        com.android.systemui.customization.R.dimen.small_clock_height
-                    ),
+                    resources.getDimensionPixelSize(customR.dimen.small_clock_height),
                 )
             layoutParams.topMargin =
                 SystemBarUtils.getStatusBarHeight(previewContext) +
-                    resources.getDimensionPixelSize(
-                        com.android.systemui.customization.R.dimen.small_clock_padding_top
-                    )
+                    resources.getDimensionPixelSize(customR.dimen.small_clock_padding_top)
             smallClockHostView.layoutParams = layoutParams
             smallClockHostView.setPaddingRelative(
-                /* start = */ resources.getDimensionPixelSize(
-                    com.android.systemui.customization.R.dimen.clock_padding_start
-                ),
+                /* start = */ resources.getDimensionPixelSize(customR.dimen.clock_padding_start),
                 /* top = */ 0,
                 /* end = */ 0,
                 /* bottom = */ 0,
@@ -637,7 +646,7 @@
         onClockChanged()
     }
 
-    private suspend fun updateClockAppearance(clock: ClockController) {
+    private suspend fun updateClockAppearance(clock: ClockController, resources: Resources) {
         if (!MigrateClocksToBlueprint.isEnabled) {
             clockController.clock = clock
         }
@@ -667,6 +676,11 @@
         if (MigrateClocksToBlueprint.isEnabled) {
             clockController.clock = clock
         }
+        // When set clock to clockController,it will reset fontsize based on context.resources
+        // We need to override it with overlaid resources
+        clock.largeClock.events.onFontSettingChanged(
+            resources.getDimensionPixelSize(customR.dimen.large_clock_text_size).toFloat()
+        )
     }
 
     private fun onClockChanged() {
@@ -676,7 +690,7 @@
         coroutineScope.launch {
             val clock = clockRegistry.createCurrentClock()
             clockController.clock = clock
-            updateClockAppearance(clock)
+            updateClockAppearance(clock, context.resources)
             updateLargeClock(clock)
             updateSmallClock(clock)
         }
@@ -742,12 +756,14 @@
         smallClockHostView.addView(clock.smallClock.view)
     }
 
-    /*
-     * When multi_crop_preview_ui_flag is on, we can preview portrait in split shadow direction
-     * or vice versa. So we need to decide preview direction by width and height
-     */
-    private fun previewInSplitShade(): Boolean {
-        return width > height
+    private fun getPreviewShadeLayoutWide(display: Display): Boolean {
+        return if (display.displayId == 0) {
+            shadeInteractor.isShadeLayoutWide.value
+        } else {
+            // For the unfolded preview in a folded screen; it's landscape by default
+            // For the folded preview in an unfolded screen; it's portrait by default
+            display.name == "Inner Display"
+        }
     }
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt
index 8622ffc..160380b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt
@@ -19,6 +19,7 @@
 
 import android.content.Context
 import android.view.View
+import android.view.ViewGroup
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
@@ -47,11 +48,15 @@
             visibility = View.GONE
         }
     }
+
     override fun addViews(constraintLayout: ConstraintLayout) {
         if (!MigrateClocksToBlueprint.isEnabled) {
             return
         }
-
+        if (emptyView.parent != null) {
+            // As emptyView is lazy, it might be already attached.
+            (emptyView.parent as? ViewGroup)?.removeView(emptyView)
+        }
         constraintLayout.addView(emptyView)
         burnInLayer =
             AodBurnInLayer(context).apply {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
index 6c98d5b..70bf8bc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
@@ -235,9 +235,7 @@
 
             val smallClockBottom =
                 keyguardClockViewModel.getSmallClockTopMargin() +
-                    context.resources.getDimensionPixelSize(
-                        com.android.systemui.customization.R.dimen.small_clock_height
-                    )
+                    context.resources.getDimensionPixelSize(customR.dimen.small_clock_height)
             val dateWeatherSmartspaceHeight = getDimen(context, DATE_WEATHER_VIEW_HEIGHT).toFloat()
             val marginBetweenSmartspaceAndNotification =
                 context.resources.getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModel.kt
index f0bccac..85ce5cd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModel.kt
@@ -23,7 +23,9 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
 import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
 import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.ui.composable.transitions.TO_BOUNCER_FADE_FRACTION
 import javax.inject.Inject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
@@ -36,9 +38,7 @@
 @SysUISingleton
 class AlternateBouncerToPrimaryBouncerTransitionViewModel
 @Inject
-constructor(
-    animationFlow: KeyguardTransitionAnimationFlow,
-) : DeviceEntryIconTransition {
+constructor(animationFlow: KeyguardTransitionAnimationFlow) : DeviceEntryIconTransition {
     private val transitionAnimation =
         animationFlow
             .setup(
@@ -46,9 +46,23 @@
                 edge = Edge.create(from = ALTERNATE_BOUNCER, to = Scenes.Bouncer),
             )
             .setupWithoutSceneContainer(
-                edge = Edge.create(from = ALTERNATE_BOUNCER, to = PRIMARY_BOUNCER),
+                edge = Edge.create(from = ALTERNATE_BOUNCER, to = PRIMARY_BOUNCER)
             )
 
+    private val alphaForAnimationStep: (Float) -> Float =
+        when {
+            SceneContainerFlag.isEnabled -> { step ->
+                    1f - Math.min((step / TO_BOUNCER_FADE_FRACTION), 1f)
+                }
+            else -> { step -> 1f - step }
+        }
+
+    val lockscreenAlpha: Flow<Float> =
+        transitionAnimation.sharedFlow(
+            duration = FromAlternateBouncerTransitionInteractor.TO_PRIMARY_BOUNCER_DURATION,
+            onStep = alphaForAnimationStep,
+        )
+
     override val deviceEntryParentViewAlpha: Flow<Float> =
         transitionAnimation.immediatelyTransitionTo(0f)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
index 3a7a640..6e30e48 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
+import android.content.Context
 import android.content.res.Resources
 import androidx.annotation.VisibleForTesting
 import androidx.constraintlayout.helper.widget.Layer
@@ -27,7 +28,8 @@
 import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
 import com.android.systemui.keyguard.shared.model.ClockSize
 import com.android.systemui.keyguard.shared.model.ClockSizeSetting
-import com.android.systemui.res.R
+import com.android.systemui.plugins.clocks.ClockPreviewConfig
+import com.android.systemui.plugins.clocks.DefaultClockFaceLayout.Companion.getSmallClockTopPadding
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -46,6 +48,7 @@
 class KeyguardClockViewModel
 @Inject
 constructor(
+    val context: Context,
     keyguardClockInteractor: KeyguardClockInteractor,
     @Application private val applicationScope: CoroutineScope,
     aodNotificationIconViewModel: NotificationIconContainerAlwaysOnDisplayViewModel,
@@ -158,16 +161,15 @@
             )
 
     /** Calculates the top margin for the small clock. */
-    fun getSmallClockTopMargin(): Int {
-        val statusBarHeight = systemBarUtils.getStatusBarHeaderHeightKeyguard()
-        return if (shadeInteractor.isShadeLayoutWide.value) {
-            resources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin) -
-                if (SceneContainerFlag.isEnabled) statusBarHeight else 0
-        } else {
-            resources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) +
-                if (!SceneContainerFlag.isEnabled) statusBarHeight else 0
-        }
-    }
+    fun getSmallClockTopMargin(): Int =
+        getSmallClockTopPadding(
+            ClockPreviewConfig(
+                context,
+                shadeInteractor.isShadeLayoutWide.value,
+                SceneContainerFlag.isEnabled,
+            ),
+            systemBarUtils.getStatusBarHeaderHeightKeyguard(),
+        )
 
     val smallClockTopMargin =
         combine(
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 65c0f57..1c44982 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,11 +17,12 @@
 package com.android.systemui.keyguard.ui.viewmodel
 
 import android.content.Context
-import com.android.internal.policy.SystemBarUtils
 import com.android.systemui.customization.R as customR
 import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
 import com.android.systemui.keyguard.shared.model.ClockSizeSetting
-import com.android.systemui.res.R
+import com.android.systemui.plugins.clocks.ClockPreviewConfig
+import com.android.systemui.plugins.clocks.DefaultClockFaceLayout.Companion.getSmallClockTopPadding
+import com.android.systemui.statusbar.ui.SystemBarUtilsProxy
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.StateFlow
@@ -35,6 +36,7 @@
     interactor: KeyguardClockInteractor,
     val smartspaceViewModel: KeyguardSmartspaceViewModel,
     val clockViewModel: KeyguardClockViewModel,
+    private val systemBarUtils: SystemBarUtilsProxy,
 ) {
 
     val selectedClockSize: StateFlow<ClockSizeSetting> = interactor.selectedClockSize
@@ -59,29 +61,18 @@
         return KeyguardSmartspaceViewModel.getSmartspaceEndMargin(context)
     }
 
-    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, context: Context): Int {
-        return getSmallClockTopPadding(splitShadePreview, context)
-    }
-
     /*
      * SmallClockTopPadding decides the top position of smartspace
      */
-    private fun getSmallClockTopPadding(splitShadePreview: Boolean, context: Context): Int {
-        return with(context.resources) {
-            if (splitShadePreview) {
-                getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin)
-            } else {
-                getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) +
-                    SystemBarUtils.getStatusBarHeight(context) +
-                    getDimensionPixelSize(customR.dimen.keyguard_smartspace_top_offset)
-            }
-        }
+    fun getSmallClockSmartspaceTopPadding(config: ClockPreviewConfig): Int {
+        return getSmallClockTopPadding(config, systemBarUtils.getStatusBarHeaderHeightKeyguard()) +
+            config.previewContext.resources.getDimensionPixelSize(customR.dimen.small_clock_height)
+    }
+
+    fun getLargeClockSmartspaceTopPadding(clockPreviewConfig: ClockPreviewConfig): Int {
+        return getSmallClockTopPadding(
+            clockPreviewConfig,
+            systemBarUtils.getStatusBarHeaderHeightKeyguard(),
+        )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt
index 6f29004..618b047 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt
@@ -23,6 +23,7 @@
 import com.android.compose.animation.scene.UserActionResult
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
+import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.ui.viewmodel.UserActionsViewModel
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -44,6 +45,7 @@
     private val deviceEntryInteractor: DeviceEntryInteractor,
     private val communalInteractor: CommunalInteractor,
     private val shadeInteractor: ShadeInteractor,
+    private val occlusionInteractor: SceneContainerOcclusionInteractor,
 ) : UserActionsViewModel() {
 
     override suspend fun hydrateActions(setActions: (Map<UserAction, UserActionResult>) -> Unit) {
@@ -57,7 +59,8 @@
                     deviceEntryInteractor.isUnlocked,
                     communalInteractor.isCommunalAvailable,
                     shadeInteractor.shadeMode,
-                ) { isDeviceUnlocked, isCommunalAvailable, shadeMode ->
+                    occlusionInteractor.isOccludingActivityShown,
+                ) { isDeviceUnlocked, isCommunalAvailable, shadeMode, isOccluded ->
                     buildList {
                             if (isCommunalAvailable) {
                                 add(Swipe.Start to Scenes.Communal)
@@ -67,7 +70,8 @@
 
                             addAll(
                                 when (shadeMode) {
-                                    ShadeMode.Single -> singleShadeActions()
+                                    ShadeMode.Single ->
+                                        singleShadeActions(isDownFromTopEdgeEnabled = !isOccluded)
                                     ShadeMode.Split -> splitShadeActions()
                                     ShadeMode.Dual -> dualShadeActions()
                                 }
diff --git a/packages/SystemUI/src/com/android/systemui/lifecycle/Hydrator.kt b/packages/SystemUI/src/com/android/systemui/lifecycle/Hydrator.kt
index 881228d..93ecae3 100644
--- a/packages/SystemUI/src/com/android/systemui/lifecycle/Hydrator.kt
+++ b/packages/SystemUI/src/com/android/systemui/lifecycle/Hydrator.kt
@@ -21,11 +21,11 @@
 import androidx.compose.runtime.snapshots.StateFactoryMarker
 import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.app.tracing.coroutines.traceCoroutine
+import com.android.systemui.log.table.TableLogBuffer
 import kotlinx.coroutines.awaitCancellation
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.StateFlow
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 /**
  * Keeps snapshot/Compose [State]s up-to-date.
@@ -47,6 +47,12 @@
      * concatenation or templating.
      */
     private val traceName: String,
+    /**
+     * An optional [TableLogBuffer] to log emissions to the states. [traceName] will be used as the
+     * prefix for the columns logged by this [Hydrator], allowing to aggregate multiple hydrators in
+     * the same table.
+     */
+    private val tableLogBuffer: TableLogBuffer? = null,
 ) : ExclusiveActivatable() {
 
     private val children = mutableListOf<NamedActivatable>()
@@ -62,15 +68,8 @@
      *   automatically set on the returned [State].
      */
     @StateFactoryMarker
-    fun <T> hydratedStateOf(
-        traceName: String,
-        source: StateFlow<T>,
-    ): State<T> {
-        return hydratedStateOf(
-            traceName = traceName,
-            initialValue = source.value,
-            source = source,
-        )
+    fun <T> hydratedStateOf(traceName: String, source: StateFlow<T>): State<T> {
+        return hydratedStateOf(traceName = traceName, initialValue = source.value, source = source)
     }
 
     /**
@@ -81,26 +80,44 @@
      *   performance findings with actual code. One recommendation: prefer whole string literals
      *   instead of some complex concatenation or templating scheme. Use `null` to disable
      *   performance tracing for this state.
+     *
+     *   If a [TableLogBuffer] was provided, every emission to the flow will be logged using the
+     *   [traceName] as the column name. For this to work correctly, all the states in the same
+     *   hydrator should have different [traceName]. Use `null` to disable logging for this state.
+     *
      * @param initialValue The first value to place on the [State]
      * @param source The upstream [Flow] to collect from; values emitted to it will be automatically
      *   set on the returned [State].
      */
     @StateFactoryMarker
-    fun <T> hydratedStateOf(
-        traceName: String?,
-        initialValue: T,
-        source: Flow<T>,
-    ): State<T> {
+    fun <T> hydratedStateOf(traceName: String?, initialValue: T, source: Flow<T>): State<T> {
         check(!isActive) { "Cannot call hydratedStateOf after Hydrator is already active." }
 
         val mutableState = mutableStateOf(initialValue)
+        traceName?.let { name ->
+            tableLogBuffer?.logChange(
+                prefix = this.traceName,
+                columnName = name,
+                value = initialValue?.toString(),
+                isInitial = true,
+            )
+        }
         children.add(
             NamedActivatable(
                 traceName = traceName,
                 activatable =
                     object : ExclusiveActivatable() {
                         override suspend fun onActivated(): Nothing {
-                            source.collect { mutableState.value = it }
+                            source.collect {
+                                traceName?.let { name ->
+                                    tableLogBuffer?.logChange(
+                                        prefix = this@Hydrator.traceName,
+                                        columnName = name,
+                                        value = it?.toString(),
+                                    )
+                                }
+                                mutableState.value = it
+                            }
                             awaitCancellation()
                         }
                     },
@@ -122,8 +139,5 @@
         }
     }
 
-    private data class NamedActivatable(
-        val traceName: String?,
-        val activatable: Activatable,
-    )
+    private data class NamedActivatable(val traceName: String?, val activatable: Activatable)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
index b69b25d..8fbbb8b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
@@ -813,8 +813,15 @@
     }
 
     private void attachConnectNewDeviceItemIfNeeded(List<MediaItem> mediaItems) {
+        boolean isSelectedDeviceNotAGroup = getSelectedMediaDevice().size() == 1;
+        if (enableInputRouting()) {
+            // When input routing is enabled, there are expected to be at least 2 total selected
+            // devices: one output device and one input device.
+            isSelectedDeviceNotAGroup = getSelectedMediaDevice().size() <= 2;
+        }
+
         // Attach "Connect a device" item only when current output is not remote and not a group
-        if (!isCurrentConnectedDeviceRemote() && getSelectedMediaDevice().size() == 1) {
+        if (!isCurrentConnectedDeviceRemote() && isSelectedDeviceNotAGroup) {
             mediaItems.add(MediaItem.createPairNewDeviceMediaItem());
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt
index 35efd75..7d30948 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt
@@ -20,6 +20,7 @@
 import android.hardware.display.DisplayManager
 import android.media.projection.MediaProjectionInfo
 import android.media.projection.MediaProjectionManager
+import android.media.projection.StopReason
 import android.os.Handler
 import android.view.ContentRecordingSession
 import android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY
@@ -72,7 +73,7 @@
         }
     }
 
-    override suspend fun stopProjecting() {
+    override suspend fun stopProjecting(@StopReason stopReason: Int) {
         withContext(backgroundDispatcher) {
             logger.log(
                 TAG,
@@ -80,7 +81,7 @@
                 {},
                 { "Requesting MediaProjectionManager#stopActiveProjection" },
             )
-            mediaProjectionManager.stopActiveProjection()
+            mediaProjectionManager.stopActiveProjection(stopReason)
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt
index 50182d7..a01d8c2 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.mediaprojection.data.repository
 
 import android.app.ActivityManager.RunningTaskInfo
+import android.media.projection.StopReason
 import com.android.systemui.mediaprojection.data.model.MediaProjectionState
 import kotlinx.coroutines.flow.Flow
 
@@ -27,7 +28,7 @@
     suspend fun switchProjectedTask(task: RunningTaskInfo)
 
     /** Stops the currently active projection. */
-    suspend fun stopProjecting()
+    suspend fun stopProjecting(@StopReason stopReason: Int)
 
     /** Represents the current [MediaProjectionState]. */
     val mediaProjectionState: Flow<MediaProjectionState>
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
index a3b7590..d2b1d54 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
@@ -56,7 +56,7 @@
 import com.android.systemui.shared.statusbar.phone.BarTransitions.TransitionMode;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.AutoHideControllerStore;
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.util.Utils;
@@ -124,7 +124,7 @@
             TaskbarDelegate taskbarDelegate,
             NavigationBarComponent.Factory navigationBarComponentFactory,
             DumpManager dumpManager,
-            AutoHideController autoHideController,
+            AutoHideControllerStore autoHideControllerStore,
             LightBarController lightBarController,
             TaskStackChangeListeners taskStackChangeListeners,
             Optional<Pip> pipOptional,
@@ -146,8 +146,9 @@
         mTaskbarDelegate = taskbarDelegate;
         mTaskbarDelegate.setDependencies(commandQueue, overviewProxyService,
                 navBarHelper, navigationModeController, sysUiFlagsContainer,
-                dumpManager, autoHideController, lightBarController, pipOptional,
-                backAnimation.orElse(null), taskStackChangeListeners);
+                dumpManager, autoHideControllerStore.forDisplay(mContext.getDisplayId()),
+                lightBarController, pipOptional, backAnimation.orElse(null),
+                taskStackChangeListeners);
         mIsLargeScreen = isLargeScreen(mContext);
         mIsPhone = determineIfPhone(mContext, deviceStateManager);
         dumpManager.registerDumpable(this);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 80ac2fc..0a4e8c6 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -18,6 +18,7 @@
 import static android.content.pm.ActivityInfo.CONFIG_FONT_SCALE;
 import static android.view.InputDevice.SOURCE_MOUSE;
 import static android.view.InputDevice.SOURCE_TOUCHPAD;
+import static android.view.MotionEvent.TOOL_TYPE_FINGER;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
 
 import static com.android.systemui.Flags.edgebackGestureHandlerGetRunningTasksBackground;
@@ -216,6 +217,7 @@
     private final int mDisplayId;
 
     private final UiThreadContext mUiThreadContext;
+    private final Handler mBgHandler;
     private final Executor mBackgroundExecutor;
 
     private final Rect mPipExcludedBounds = new Rect();
@@ -378,11 +380,14 @@
         @Override
         public void onInputDeviceAdded(int deviceId) {
             if (isTrackpadDevice(deviceId)) {
-                boolean wasEmpty = mTrackpadsConnected.isEmpty();
-                mTrackpadsConnected.add(deviceId);
-                if (wasEmpty) {
-                    update();
-                }
+                // This updates the gesture handler state and should be running on the main thread.
+                mUiThreadContext.getHandler().post(() -> {
+                    boolean wasEmpty = mTrackpadsConnected.isEmpty();
+                    mTrackpadsConnected.add(deviceId);
+                    if (wasEmpty) {
+                        update();
+                    }
+                });
             }
         }
 
@@ -391,10 +396,13 @@
 
         @Override
         public void onInputDeviceRemoved(int deviceId) {
-            mTrackpadsConnected.remove(deviceId);
-            if (mTrackpadsConnected.isEmpty()) {
-                update();
-            }
+            // This updates the gesture handler state and should be running on the main thread.
+            mUiThreadContext.getHandler().post(() -> {
+                mTrackpadsConnected.remove(deviceId);
+                if (mTrackpadsConnected.isEmpty()) {
+                    update();
+                }
+            });
         }
 
         private void update() {
@@ -408,12 +416,12 @@
         }
 
         private boolean isTrackpadDevice(int deviceId) {
+            // This is a blocking binder call that should run on a bg thread.
             InputDevice inputDevice = mInputManager.getInputDevice(deviceId);
             if (inputDevice == null) {
                 return false;
             }
-            return inputDevice.getSources() == (InputDevice.SOURCE_MOUSE
-                    | InputDevice.SOURCE_TOUCHPAD);
+            return inputDevice.getSources() == (SOURCE_MOUSE | SOURCE_TOUCHPAD);
         }
     };
 
@@ -457,6 +465,7 @@
         mDisplayId = context.getDisplayId();
         mUiThreadContext = uiThreadContext;
         mBackgroundExecutor = backgroundExecutor;
+        mBgHandler = bgHandler;
         mUserTracker = userTracker;
         mOverviewProxyService = overviewProxyService;
         mSysUiState = sysUiState;
@@ -611,9 +620,7 @@
         mIsAttached = true;
         mOverviewProxyService.addCallback(mQuickSwitchListener);
         mSysUiState.addCallback(mSysUiStateCallback);
-        mInputManager.registerInputDeviceListener(
-                mInputDeviceListener,
-                mUiThreadContext.getHandler());
+        mInputManager.registerInputDeviceListener(mInputDeviceListener, mBgHandler);
         int[] inputDevices = mInputManager.getInputDeviceIds();
         for (int inputDeviceId : inputDevices) {
             mInputDeviceListener.onInputDeviceAdded(inputDeviceId);
@@ -1089,8 +1096,8 @@
                         && isValidTrackpadBackGesture(true /* isTrackpadEvent */);
             } else {
                 mAllowGesture = isBackAllowedCommon && !mUsingThreeButtonNav && isWithinInsets
-                    && isWithinTouchRegion((int) ev.getX(), (int) ev.getY())
-                    && !isButtonPressFromTrackpad(ev);
+                        && isWithinTouchRegion((int) ev.getX(), (int) ev.getY())
+                        && !isButtonPressFromTrackpad(ev);
             }
             if (mAllowGesture) {
                 mEdgeBackPlugin.setIsLeftPanel(mIsOnLeftEdge);
@@ -1202,10 +1209,8 @@
     }
 
     private boolean isButtonPressFromTrackpad(MotionEvent ev) {
-        // We don't allow back for button press from the trackpad, and yet we do with a mouse.
-        int sources = InputManager.getInstance().getInputDevice(ev.getDeviceId()).getSources();
-        int sourceTrackpad = (SOURCE_MOUSE | SOURCE_TOUCHPAD);
-        return (sources & sourceTrackpad) == sourceTrackpad && ev.getButtonState() != 0;
+        return ev.getSource() == (SOURCE_MOUSE | SOURCE_TOUCHPAD)
+                && ev.getToolType(ev.getActionIndex()) == TOOL_TYPE_FINGER;
     }
 
     private void dispatchToBackAnimation(MotionEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
index 40613c0..c895732 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
@@ -149,9 +149,9 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.data.repository.LightBarControllerStore;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.AutoHideControllerStore;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -259,10 +259,10 @@
     private boolean mTransientShownFromGestureOnSystemBar;
     private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
     private LightBarController mLightBarController;
-    private final LightBarControllerStore mLightBarControllerStore;
+    private final LightBarController mMainLightBarController;
+    private final LightBarController.Factory mLightBarControllerFactory;
     private AutoHideController mAutoHideController;
-    private final AutoHideController mMainAutoHideController;
-    private final AutoHideController.Factory mAutoHideControllerFactory;
+    private final AutoHideControllerStore mAutoHideControllerStore;
     private final Optional<TelecomManager> mTelecomManagerOptional;
     private final InputMethodManager mInputMethodManager;
     private final TaskStackChangeListeners mTaskStackChangeListeners;
@@ -580,9 +580,9 @@
             @Background Executor bgExecutor,
             UiEventLogger uiEventLogger,
             NavBarHelper navBarHelper,
-            LightBarControllerStore lightBarControllerStore,
-            AutoHideController mainAutoHideController,
-            AutoHideController.Factory autoHideControllerFactory,
+            LightBarController mainLightBarController,
+            LightBarController.Factory lightBarControllerFactory,
+            AutoHideControllerStore autoHideControllerStore,
             Optional<TelecomManager> telecomManagerOptional,
             InputMethodManager inputMethodManager,
             DeadZone deadZone,
@@ -627,9 +627,9 @@
         mUiEventLogger = uiEventLogger;
         mNavBarHelper = navBarHelper;
         mNotificationShadeDepthController = notificationShadeDepthController;
-        mLightBarControllerStore = lightBarControllerStore;
-        mMainAutoHideController = mainAutoHideController;
-        mAutoHideControllerFactory = autoHideControllerFactory;
+        mMainLightBarController = mainLightBarController;
+        mLightBarControllerFactory = lightBarControllerFactory;
+        mAutoHideControllerStore = autoHideControllerStore;
         mTelecomManagerOptional = telecomManagerOptional;
         mInputMethodManager = inputMethodManager;
         mUserContextProvider = userContextProvider;
@@ -840,16 +840,11 @@
         // Unfortunately, we still need it because status bar needs LightBarController
         // before notifications creation. We cannot directly use getLightBarController()
         // from NavigationBarFragment directly.
-        LightBarController lightBarController = mLightBarControllerStore.forDisplay(mDisplayId);
+        LightBarController lightBarController = mIsOnDefaultDisplay
+                ? mMainLightBarController : mLightBarControllerFactory.create(mContext);
         setLightBarController(lightBarController);
 
-        // TODO(b/118592525): to support multi-display, we start to add something which is
-        //                    per-display, while others may be global. I think it's time to
-        //                    add a new class maybe named DisplayDependency to solve
-        //                    per-display Dependency problem.
-        // Alternative: this is a good case for a Dagger subcomponent. Same with LightBarController.
-        AutoHideController autoHideController = mIsOnDefaultDisplay
-                ? mMainAutoHideController : mAutoHideControllerFactory.create(mContext);
+        AutoHideController autoHideController = mAutoHideControllerStore.forDisplay(mDisplayId);
         setAutoHideController(autoHideController);
         restoreAppearanceAndTransientState();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
index d715f42..dc188c2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -16,8 +16,11 @@
 
 package com.android.systemui.qs;
 
+import static com.android.systemui.Flags.gsfQuickSettings;
+
 import android.content.ClipData;
 import android.content.ClipboardManager;
+import android.graphics.Typeface;
 import android.text.TextUtils;
 import android.view.View;
 import android.widget.TextView;
@@ -64,6 +67,9 @@
         mRetailModeInteractor = retailModeInteractor;
 
         mBuildText = mView.findViewById(R.id.build);
+        if (gsfQuickSettings()) {
+            mBuildText.setTypeface(Typeface.create("gsf-body-medium", Typeface.NORMAL));
+        }
         mPageIndicator = mView.findViewById(R.id.footer_page_indicator);
         mEditButton = mView.findViewById(android.R.id.edit);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
index 21c45c5..9dc21fb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
@@ -233,6 +233,7 @@
                 // Only allow scrolling when we are fully expanded. That way, we don't intercept
                 // swipes in lockscreen (when somehow QS is receiving touches).
                 { (scrollState.canScrollForward && viewModel.isQsFullyExpanded) || isCustomizing },
+                viewModel::emitMotionEventForFalsingSwipeNested,
             )
         frame.addView(
             composeView,
@@ -628,11 +629,7 @@
                                         id = R.string.accessibility_quick_settings_expand
                                     )
                                 )
-                                .padding(
-                                    horizontal = {
-                                        QuickSettingsShade.Dimensions.Padding.roundToPx()
-                                    }
-                                )
+                                .padding(horizontal = qsHorizontalMargin())
                     ) {
                         QuickQuickSettingsLayout(
                             tiles = Tiles,
@@ -718,7 +715,6 @@
                                                     max =
                                                         QuickSettingsShade.Dimensions.GridMaxHeight
                                                 ),
-                                        containerViewModel.editModeViewModel::startEditing,
                                     )
                                 }
                             }
@@ -737,8 +733,8 @@
                                     .sysuiResTag(ResIdTags.quickSettingsPanel)
                                     .padding(
                                         top = QuickSettingsShade.Dimensions.Padding,
-                                        start = QuickSettingsShade.Dimensions.Padding,
-                                        end = QuickSettingsShade.Dimensions.Padding,
+                                        start = qsHorizontalMargin(),
+                                        end = qsHorizontalMargin(),
                                     )
                         ) {
                             QuickSettingsLayout(
@@ -951,6 +947,7 @@
     private val clippingEnabledProvider: () -> Boolean,
     private val clippingTopProvider: () -> Int,
     private val canScrollForwardQs: () -> Boolean,
+    private val emitMotionEventForFalsing: () -> Unit,
 ) : FrameLayout(context) {
     override fun isTransformedTouchPointInView(
         x: Float,
@@ -967,6 +964,32 @@
 
     val touchSlop = ViewConfiguration.get(context).scaledTouchSlop
     var downY = 0f
+    var preventingIntercept = false
+
+    override fun onTouchEvent(event: MotionEvent): Boolean {
+        val action = event.actionMasked
+        when (action) {
+            MotionEvent.ACTION_DOWN -> {
+                preventingIntercept = false
+                if (canScrollVertically(1)) {
+                    // If we can scroll down, make sure we're not intercepted by the parent
+                    preventingIntercept = true
+                    parent?.requestDisallowInterceptTouchEvent(true)
+                } else if (!canScrollVertically(-1)) {
+                    // Don't pass on the touch to the view, because scrolling will unconditionally
+                    // disallow interception even if we can't scroll.
+                    // if a user can't scroll at all, we should never listen to the touch.
+                    return false
+                }
+            }
+            MotionEvent.ACTION_UP -> {
+                if (preventingIntercept) {
+                    emitMotionEventForFalsing()
+                }
+            }
+        }
+        return super.onTouchEvent(event)
+    }
 
     override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
         // If there's a touch on this view and we can scroll down, we don't want to be intercepted
@@ -974,8 +997,10 @@
 
         when (action) {
             MotionEvent.ACTION_DOWN -> {
+                preventingIntercept = false
                 // If we can scroll down, make sure none of our parents intercepts us.
                 if (canScrollForwardQs()) {
+                    preventingIntercept = true
                     parent?.requestDisallowInterceptTouchEvent(true)
                 }
                 downY = ev.y
@@ -1098,6 +1123,8 @@
     const val qsFooterActions = "qs_footer_actions"
 }
 
+@Composable private fun qsHorizontalMargin() = dimensionResource(id = R.dimen.qs_horizontal_margin)
+
 @Composable
 private fun interactionsConfig() =
     InteractionsConfig(
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeLog.kt
similarity index 73%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeLog.kt
index 7d3d8b9..5f151eb 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeLog.kt
@@ -13,10 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
-}
+package com.android.systemui.qs.composefragment.dagger
+
+import javax.inject.Qualifier
+
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class QSFragmentComposeLog
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeModule.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeModule.kt
index 2ec7292..4c9df11 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeModule.kt
@@ -18,7 +18,8 @@
 
 import android.content.Context
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.TableLogBufferFactory
 import com.android.systemui.qs.flags.QSComposeFragment
 import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.util.Utils
@@ -38,5 +39,14 @@
         fun providesUsingMedia(@ShadeDisplayAware context: Context): Boolean {
             return QSComposeFragment.isEnabled && Utils.useQsMediaPlayer(context)
         }
+
+        @Provides
+        @SysUISingleton
+        @QSFragmentComposeLog
+        fun providesQSFragmentComposeViewModelTableLog(
+            factory: TableLogBufferFactory
+        ): TableLogBuffer {
+            return factory.create("QSFragmentComposeViewModel", 200)
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt
index e3de6d5..02498d6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt
@@ -31,6 +31,8 @@
 import com.android.keyguard.BouncerPanelExpansionCalculator
 import com.android.systemui.Dumpable
 import com.android.systemui.animation.ShadeInterpolation
+import com.android.systemui.classifier.Classifier
+import com.android.systemui.classifier.domain.interactor.FalsingInteractor
 import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
@@ -39,6 +41,7 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.lifecycle.ExclusiveActivatable
 import com.android.systemui.lifecycle.Hydrator
+import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
 import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager.Companion.LOCATION_QQS
 import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager.Companion.LOCATION_QS
@@ -48,6 +51,7 @@
 import com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.qs.FooterActionsController
+import com.android.systemui.qs.composefragment.dagger.QSFragmentComposeLog
 import com.android.systemui.qs.composefragment.dagger.QSFragmentComposeModule
 import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
 import com.android.systemui.qs.panels.domain.interactor.TileSquishinessInteractor
@@ -100,7 +104,9 @@
     @ShadeDisplayAware configurationInteractor: ConfigurationInteractor,
     private val largeScreenHeaderHelper: LargeScreenHeaderHelper,
     private val squishinessInteractor: TileSquishinessInteractor,
+    private val falsingInteractor: FalsingInteractor,
     private val inFirstPageViewModel: InFirstPageViewModel,
+    @QSFragmentComposeLog private val tableLogBuffer: TableLogBuffer,
     mediaInRowInLandscapeViewModelFactory: MediaInRowInLandscapeViewModel.Factory,
     @Named(QUICK_QS_PANEL) val qqsMediaHost: MediaHost,
     @Named(QS_PANEL) val qsMediaHost: MediaHost,
@@ -112,7 +118,7 @@
     private val qqsMediaInRowViewModel = mediaInRowInLandscapeViewModelFactory.create(LOCATION_QQS)
     private val qsMediaInRowViewModel = mediaInRowInLandscapeViewModelFactory.create(LOCATION_QS)
 
-    private val hydrator = Hydrator("QSFragmentComposeViewModel.hydrator")
+    private val hydrator = Hydrator("QSFragmentComposeViewModel.hydrator", tableLogBuffer)
 
     val footerActionsViewModel =
         footerActionsViewModelFactory.create(lifecycleScope).also {
@@ -434,6 +440,10 @@
         }
     }
 
+    fun emitMotionEventForFalsingSwipeNested() {
+        falsingInteractor.isFalseTouch(Classifier.QS_SWIPE_NESTED)
+    }
+
     override suspend fun onActivated(): Nothing {
         initMediaHosts() // init regardless of using media (same as current QS).
         coroutineScope {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index f8d4080..0e64820 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -15,6 +15,8 @@
  */
 package com.android.systemui.qs.customize;
 
+import static com.android.systemui.Flags.gsfQuickSettings;
+
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
 import android.animation.AnimatorListenerAdapter;
@@ -81,6 +83,10 @@
         mToolbar.getMenu().add(Menu.NONE, MENU_RESET, 0, com.android.internal.R.string.reset)
                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
         mToolbar.setTitle(R.string.qs_edit);
+        if (gsfQuickSettings()) {
+            mToolbar.setTitleTextAppearance(context, R.style.TextAppearance_QSEditTitle);
+        }
+
         mRecyclerView = findViewById(android.R.id.list);
         mTransparentView = findViewById(R.id.customizer_transparent_view);
         DefaultItemAnimator animator = new DefaultItemAnimator();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 829c419..db778a2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -14,12 +14,15 @@
 
 package com.android.systemui.qs.customize;
 
+import static com.android.systemui.Flags.gsfQuickSettings;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.view.LayoutInflater;
@@ -309,6 +312,10 @@
         if (viewType == TYPE_HEADER) {
             View v = inflater.inflate(R.layout.qs_customize_header, parent, false);
             v.setMinimumHeight(calculateHeaderMinHeight(context));
+            if (gsfQuickSettings()) {
+                ((TextView) v.findViewById(android.R.id.title)).setTypeface(
+                        Typeface.create("gsf-label-large", Typeface.NORMAL));
+            }
             return new Holder(v);
         }
         if (viewType == TYPE_DIVIDER) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/flags/QsInCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/flags/QsInCompose.kt
new file mode 100644
index 0000000..3067ccb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/flags/QsInCompose.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.qs.flags
+
+import com.android.systemui.flags.RefactorFlagUtils
+import com.android.systemui.shade.shared.flag.DualShade
+
+/**
+ * Object to help check if the new QS ui should be used. This is true if either [QSComposeFragment]
+ * or [DualShade] are enabled.
+ */
+object QsInCompose {
+
+    /**
+     * This is not a real flag name, but a representation of the allowed flag names. Should not be
+     * used with test annotations.
+     */
+    private val flagName = "${QSComposeFragment.FLAG_NAME}|${DualShade.FLAG_NAME}"
+
+    @JvmStatic
+    inline val isEnabled: Boolean
+        get() = QSComposeFragment.isEnabled || DualShade.isEnabled
+
+    @JvmStatic
+    fun isUnexpectedlyInLegacyMode() =
+        RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, flagName)
+
+    @JvmStatic fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, flagName)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditModeButton.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditModeButton.kt
new file mode 100644
index 0000000..c2764f9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditModeButton.kt
@@ -0,0 +1,61 @@
+/*
+ * 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.qs.panels.ui.compose
+
+import androidx.compose.foundation.shape.CornerSize
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Edit
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import com.android.systemui.lifecycle.rememberViewModel
+import com.android.systemui.qs.panels.ui.viewmodel.EditModeButtonViewModel
+import com.android.systemui.qs.ui.compose.borderOnFocus
+import com.android.systemui.res.R
+
+@Composable
+fun EditModeButton(
+    viewModelFactory: EditModeButtonViewModel.Factory,
+    modifier: Modifier = Modifier,
+) {
+    val viewModel = rememberViewModel(traceName = "EditModeButton") { viewModelFactory.create() }
+    CompositionLocalProvider(
+        value = LocalContentColor provides MaterialTheme.colorScheme.onSurface
+    ) {
+        IconButton(
+            onClick = viewModel::onButtonClick,
+            shape = RoundedCornerShape(CornerSize(28.dp)),
+            modifier =
+                modifier.borderOnFocus(
+                    color = MaterialTheme.colorScheme.secondary,
+                    cornerSize = CornerSize(24.dp),
+                ),
+        ) {
+            Icon(
+                imageVector = Icons.Default.Edit,
+                contentDescription = stringResource(id = R.string.qs_edit),
+            )
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt
index c729c7c..14abfa2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt
@@ -68,29 +68,16 @@
         return _tiles.indexOfFirst { it is TileGridCell && it.tile.tileSpec == tileSpec }
     }
 
-    /**
-     * Whether the tile with this [TileSpec] is currently an icon in the [EditTileListState]
-     *
-     * @return true if the tile is an icon, false if it's large, null if the tile isn't in the list
-     */
-    fun isIcon(tileSpec: TileSpec): Boolean? {
-        val index = indexOf(tileSpec)
-        return if (index != -1) {
-            val cell = _tiles[index]
-            cell as TileGridCell
-            return cell.isIcon
-        } else {
-            null
-        }
-    }
-
-    /** Toggle the size of the tile corresponding to the [TileSpec] */
-    fun toggleSize(tileSpec: TileSpec) {
+    /** Resize the tile corresponding to the [TileSpec] to [toIcon] */
+    fun resizeTile(tileSpec: TileSpec, toIcon: Boolean) {
         val fromIndex = indexOf(tileSpec)
         if (fromIndex != -1) {
-            val cell = _tiles.removeAt(fromIndex)
-            cell as TileGridCell
-            _tiles.add(fromIndex, cell.copy(width = if (cell.isIcon) largeTilesSpan else 1))
+            val cell = _tiles[fromIndex] as TileGridCell
+
+            if (cell.isIcon == toIcon) return
+
+            _tiles.removeAt(fromIndex)
+            _tiles.add(fromIndex, cell.copy(width = if (toIcon) 1 else largeTilesSpan))
             regenerateGrid(fromIndex)
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
index 0d37581..a22eb3a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
@@ -27,12 +27,7 @@
 
 /** A layout of tiles, indicating how they should be composed when showing in QS or in edit mode. */
 interface GridLayout {
-    @Composable
-    fun SceneScope.TileGrid(
-        tiles: List<TileViewModel>,
-        modifier: Modifier,
-        editModeStart: () -> Unit,
-    )
+    @Composable fun SceneScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier)
 
     @Composable
     fun EditTileGrid(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
index 789fdeb..b6dbf4d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.panels.ui.compose
 
+import android.view.MotionEvent
 import androidx.compose.foundation.layout.Arrangement.spacedBy
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.PaddingValues
@@ -29,22 +30,15 @@
 import androidx.compose.foundation.pager.PagerState
 import androidx.compose.foundation.pager.rememberPagerState
 import androidx.compose.foundation.shape.CornerSize
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Edit
-import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
-import androidx.compose.material3.LocalContentColor
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.snapshotFlow
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.input.pointer.pointerInteropFilter
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.modifiers.padding
@@ -55,10 +49,10 @@
 import com.android.systemui.qs.panels.dagger.PaginatedBaseLayoutType
 import com.android.systemui.qs.panels.ui.compose.Dimensions.FooterHeight
 import com.android.systemui.qs.panels.ui.compose.Dimensions.InterPageSpacing
+import com.android.systemui.qs.panels.ui.viewmodel.EditModeButtonViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.PaginatedGridViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
 import com.android.systemui.qs.ui.compose.borderOnFocus
-import com.android.systemui.res.R
 import javax.inject.Inject
 
 class PaginatedGridLayout
@@ -68,11 +62,7 @@
     @PaginatedBaseLayoutType private val delegateGridLayout: PaginatableGridLayout,
 ) : GridLayout by delegateGridLayout {
     @Composable
-    override fun SceneScope.TileGrid(
-        tiles: List<TileViewModel>,
-        modifier: Modifier,
-        editModeStart: () -> Unit,
-    ) {
+    override fun SceneScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier) {
         val viewModel =
             rememberViewModel(traceName = "PaginatedGridLayout-TileGrid") {
                 viewModelFactory.create()
@@ -115,7 +105,13 @@
                 state = pagerState,
                 modifier =
                     Modifier.sysuiResTag("qs_pager")
-                        .padding(horizontal = { -contentPaddingValue.roundToPx() }),
+                        .padding(horizontal = { -contentPaddingValue.roundToPx() })
+                        .pointerInteropFilter { event ->
+                            if (event.actionMasked == MotionEvent.ACTION_UP) {
+                                viewModel.registerSideSwipeGesture()
+                            }
+                            false
+                        },
                 contentPadding = contentPadding,
                 pageSpacing = if (pages.size > 1) InterPageSpacing else 0.dp,
                 beyondViewportPageCount = 1,
@@ -123,14 +119,12 @@
             ) {
                 val page = pages[it]
 
-                with(delegateGridLayout) {
-                    TileGrid(tiles = page, modifier = Modifier, editModeStart = {})
-                }
+                with(delegateGridLayout) { TileGrid(tiles = page, modifier = Modifier) }
             }
             FooterBar(
                 buildNumberViewModelFactory = viewModel.buildNumberViewModelFactory,
                 pagerState = pagerState,
-                editModeStart = editModeStart,
+                editButtonViewModelFactory = viewModel.editModeButtonViewModelFactory,
             )
         }
     }
@@ -145,7 +139,7 @@
 private fun FooterBar(
     buildNumberViewModelFactory: BuildNumberViewModel.Factory,
     pagerState: PagerState,
-    editModeStart: () -> Unit,
+    editButtonViewModelFactory: EditModeButtonViewModel.Factory,
 ) {
     // Use requiredHeight so it won't be squished if the view doesn't quite fit. As this is
     // expected to be inside a scrollable container, this should not be an issue.
@@ -181,24 +175,7 @@
         )
         Row(Modifier.weight(1f)) {
             Spacer(modifier = Modifier.weight(1f))
-            CompositionLocalProvider(
-                value = LocalContentColor provides MaterialTheme.colorScheme.onSurface
-            ) {
-                IconButton(
-                    onClick = editModeStart,
-                    shape = RoundedCornerShape(CornerSize(28.dp)),
-                    modifier =
-                        Modifier.borderOnFocus(
-                            color = MaterialTheme.colorScheme.secondary,
-                            cornerSize = CornerSize(FooterHeight / 2),
-                        ),
-                ) {
-                    Icon(
-                        imageVector = Icons.Default.Edit,
-                        contentDescription = stringResource(id = R.string.qs_edit),
-                    )
-                }
-            }
+            EditModeButton(viewModelFactory = editButtonViewModelFactory)
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
index ca28ab3..2928ad1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
@@ -75,6 +75,8 @@
                 coroutineScope = scope,
                 bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns),
                 tileHapticsViewModelFactoryProvider = viewModel.tileHapticsViewModelFactoryProvider,
+                // There should be no QuickQuickSettings when the details view is enabled.
+                detailsViewModel = null,
             )
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileDetails.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileDetails.kt
new file mode 100644
index 0000000..1bfbbe1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileDetails.kt
@@ -0,0 +1,121 @@
+/*
+ * 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.qs.panels.ui.compose
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.filled.ArrowBack
+import androidx.compose.material.icons.filled.Settings
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.em
+import com.android.systemui.qs.flags.QsDetailedView
+import com.android.systemui.qs.panels.ui.viewmodel.DetailsViewModel
+
+@Composable
+fun TileDetails(detailsViewModel: DetailsViewModel) {
+
+    if (!QsDetailedView.isEnabled) {
+        throw IllegalStateException("QsDetailedView should be enabled")
+    }
+
+    val tileDetailedViewModel = detailsViewModel.activeTileDetails ?: return
+
+    DisposableEffect(Unit) { onDispose { detailsViewModel.closeDetailedView() } }
+
+    Column(
+        modifier = Modifier
+            .fillMaxWidth()
+            // The height of the details view is TBD.
+            .fillMaxHeight()
+    ) {
+        CompositionLocalProvider(
+            value = LocalContentColor provides MaterialTheme.colorScheme.onSurfaceVariant
+        ) {
+            Row(
+                modifier = Modifier.fillMaxWidth(),
+                horizontalArrangement = Arrangement.SpaceBetween,
+                verticalAlignment = Alignment.CenterVertically
+            ) {
+
+                IconButton(
+                    onClick = { detailsViewModel.closeDetailedView() },
+                    modifier = Modifier
+                        .align(Alignment.CenterVertically)
+                        .height(TileDetailsDefaults.IconHeight)
+                        .padding(start = TileDetailsDefaults.IconPadding),
+                ) {
+                    Icon(
+                        imageVector = Icons.AutoMirrored.Filled.ArrowBack,
+                        // Description is TBD
+                        contentDescription = "Back to QS panel",
+                    )
+                }
+                Text(
+                    text = tileDetailedViewModel.getTitle(),
+                    modifier = Modifier
+                        .align(Alignment.CenterVertically),
+                    textAlign = TextAlign.Center,
+                    style = MaterialTheme.typography.titleLarge
+                )
+                IconButton(
+                    onClick = { tileDetailedViewModel.clickOnSettingsButton() },
+                    modifier = Modifier
+                        .align(Alignment.CenterVertically)
+                        .height(TileDetailsDefaults.IconHeight)
+                        .padding(end = TileDetailsDefaults.IconPadding),
+                ) {
+                    Icon(
+                        imageVector = Icons.Default.Settings,
+                        // Description is TBD
+                        contentDescription = "Go to Settings",
+                    )
+                }
+            }
+            Text(
+                text = tileDetailedViewModel.getSubTitle(),
+                modifier = Modifier
+                    .fillMaxWidth(),
+                textAlign = TextAlign.Center,
+                style = MaterialTheme.typography.titleSmall
+
+            )
+        }
+        tileDetailedViewModel.GetContentView()
+    }
+}
+
+private object TileDetailsDefaults {
+    val IconHeight = 48.dp
+    val IconPadding = 4.dp
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
index 1a5297b..6c1906b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
@@ -24,13 +24,9 @@
 import com.android.systemui.qs.panels.ui.viewmodel.TileGridViewModel
 
 @Composable
-fun SceneScope.TileGrid(
-    viewModel: TileGridViewModel,
-    modifier: Modifier = Modifier,
-    editModeStart: () -> Unit,
-) {
+fun SceneScope.TileGrid(viewModel: TileGridViewModel, modifier: Modifier = Modifier) {
     val gridLayout by viewModel.gridLayout.collectAsStateWithLifecycle()
     val tiles by viewModel.tileViewModels.collectAsStateWithLifecycle(emptyList())
 
-    with(gridLayout) { TileGrid(tiles, modifier, editModeStart) }
+    with(gridLayout) { TileGrid(tiles, modifier) }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
index 31ea60e..c6141a1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
@@ -20,7 +20,6 @@
 
 import androidx.compose.animation.AnimatedContent
 import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.core.Animatable
 import androidx.compose.animation.core.animateDpAsState
 import androidx.compose.animation.core.animateFloatAsState
 import androidx.compose.animation.fadeIn
@@ -75,7 +74,6 @@
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.rememberUpdatedState
 import androidx.compose.runtime.setValue
-import androidx.compose.runtime.snapshotFlow
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
@@ -124,8 +122,12 @@
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.CurrentTilesGridPadding
 import com.android.systemui.qs.panels.ui.compose.selection.MutableSelectionState
 import com.android.systemui.qs.panels.ui.compose.selection.ResizableTileContainer
-import com.android.systemui.qs.panels.ui.compose.selection.TileWidths
+import com.android.systemui.qs.panels.ui.compose.selection.ResizingState
+import com.android.systemui.qs.panels.ui.compose.selection.ResizingState.ResizeOperation
+import com.android.systemui.qs.panels.ui.compose.selection.ResizingState.ResizeOperation.FinalResizeOperation
+import com.android.systemui.qs.panels.ui.compose.selection.ResizingState.ResizeOperation.TemporaryResizeOperation
 import com.android.systemui.qs.panels.ui.compose.selection.clearSelectionTile
+import com.android.systemui.qs.panels.ui.compose.selection.rememberResizingState
 import com.android.systemui.qs.panels.ui.compose.selection.rememberSelectionState
 import com.android.systemui.qs.panels.ui.compose.selection.selectableTile
 import com.android.systemui.qs.panels.ui.model.GridCell
@@ -136,10 +138,10 @@
 import com.android.systemui.qs.pipeline.shared.TileSpec
 import com.android.systemui.qs.shared.model.groupAndSort
 import com.android.systemui.res.R
+import kotlin.math.max
 import kotlin.math.roundToInt
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.collectLatest
 
 object TileType
 
@@ -181,15 +183,7 @@
     onStopEditing: () -> Unit,
     onReset: (() -> Unit)?,
 ) {
-    val currentListState by rememberUpdatedState(listState)
-    val selectionState =
-        rememberSelectionState(
-            onResize = { currentListState.toggleSize(it) },
-            onResizeEnd = { spec ->
-                // Commit the size currently in the list
-                currentListState.isIcon(spec)?.let { onResize(spec, it) }
-            },
-        )
+    val selectionState = rememberSelectionState()
     val reset: (() -> Unit)? =
         if (onReset != null) {
             {
@@ -349,10 +343,21 @@
                 }
                 .testTag(CURRENT_TILES_GRID_TEST_TAG),
     ) {
-        EditTiles(cells, columns, listState, selectionState, coroutineScope, largeTilesSpan) { spec
-            ->
-            // Toggle the current size of the tile
-            currentListState.isIcon(spec)?.let { onResize(spec, !it) }
+        EditTiles(cells, columns, listState, selectionState, coroutineScope, largeTilesSpan) {
+            resizingOperation ->
+            when (resizingOperation) {
+                is TemporaryResizeOperation -> {
+                    currentListState.resizeTile(resizingOperation.spec, resizingOperation.toIcon)
+                }
+                is FinalResizeOperation -> {
+                    // Commit the new size of the tile
+                    onResize(resizingOperation.spec, resizingOperation.toIcon)
+
+                    // Mark the selection as automatic in case the tile ends up moving to a
+                    // different row with its new size.
+                    selectionState.select(resizingOperation.spec, manual = false)
+                }
+            }
         }
     }
 }
@@ -373,7 +378,7 @@
 
     // Available tiles
     Column(
-        verticalArrangement = spacedBy(CommonTileDefaults.TileArrangementPadding),
+        verticalArrangement = spacedBy(TileArrangementPadding),
         horizontalAlignment = Alignment.Start,
         modifier =
             Modifier.fillMaxWidth().wrapContentHeight().testTag(AVAILABLE_TILES_GRID_TEST_TAG),
@@ -387,7 +392,7 @@
             )
             tiles.chunked(columns).forEach { row ->
                 Row(
-                    horizontalArrangement = spacedBy(CommonTileDefaults.TileArrangementPadding),
+                    horizontalArrangement = spacedBy(TileArrangementPadding),
                     modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Max),
                 ) {
                     row.forEachIndexed { index, tileGridCell ->
@@ -436,7 +441,7 @@
     selectionState: MutableSelectionState,
     coroutineScope: CoroutineScope,
     largeTilesSpan: Int,
-    onToggleSize: (spec: TileSpec) -> Unit,
+    onResize: (operation: ResizeOperation) -> Unit,
 ) {
     items(
         count = cells.size,
@@ -464,7 +469,7 @@
                         index = index,
                         dragAndDropState = dragAndDropState,
                         selectionState = selectionState,
-                        onToggleSize = onToggleSize,
+                        onResize = onResize,
                         coroutineScope = coroutineScope,
                         bounceableInfo = cells.bounceableInfo(index, columns),
                         largeTilesSpan = largeTilesSpan,
@@ -482,7 +487,7 @@
     index: Int,
     dragAndDropState: DragAndDropState,
     selectionState: MutableSelectionState,
-    onToggleSize: (spec: TileSpec) -> Unit,
+    onResize: (operation: ResizeOperation) -> Unit,
     coroutineScope: CoroutineScope,
     largeTilesSpan: Int,
     bounceableInfo: BounceableInfo,
@@ -511,28 +516,47 @@
         selected = selectionState.selection?.tileSpec == cell.tile.tileSpec
     }
 
-    // Current base, min and max width of this tile
-    var tileWidths: TileWidths? by remember { mutableStateOf(null) }
-    val padding = with(LocalDensity.current) { TileArrangementPadding.roundToPx() }
+    val state = rememberResizingState(cell.tile.tileSpec, cell.isIcon)
+
+    val progress: () -> Float = {
+        if (selected) {
+            // If selected, return the manual progress from the drag
+            state.progress()
+        } else {
+            // Else, return the target progress for the tile format
+            if (cell.isIcon) 0f else 1f
+        }
+    }
+
+    if (!selected) {
+        // Update the draggable anchor state when the tile's size is not manually toggled
+        LaunchedEffect(cell.isIcon) { state.updateCurrentValue(cell.isIcon) }
+    } else {
+        // If the tile is selected, listen to new target values from the draggable anchor to toggle
+        // the tile's size
+        LaunchedEffect(state.temporaryResizeOperation) { onResize(state.temporaryResizeOperation) }
+        LaunchedEffect(state.finalResizeOperation) { onResize(state.finalResizeOperation) }
+    }
+
+    val totalPadding =
+        with(LocalDensity.current) { (largeTilesSpan - 1) * TileArrangementPadding.roundToPx() }
 
     ResizableTileContainer(
         selected = selected,
-        selectionState = selectionState,
+        state = state,
         selectionAlpha = { selectionAlpha },
         selectionColor = selectionColor,
-        tileWidths = { tileWidths },
         modifier =
             modifier
                 .height(TileHeight)
                 .fillMaxWidth()
                 .onSizeChanged {
                     // Grab the size before the bounceable to get the idle width
-                    val totalPadding = (largeTilesSpan - 1) * padding
                     val min =
                         if (cell.isIcon) it.width else (it.width - totalPadding) / largeTilesSpan
                     val max =
                         if (cell.isIcon) (it.width * largeTilesSpan) + totalPadding else it.width
-                    tileWidths = TileWidths(it.width, min, max)
+                    state.updateAnchors(min.toFloat(), max.toFloat())
                 }
                 .bounceable(
                     bounceable = currentBounceableInfo.bounceable,
@@ -552,7 +576,7 @@
                         listOf(
                             // TODO(b/367748260): Add final accessibility actions
                             CustomAccessibilityAction("Toggle size") {
-                                onToggleSize(cell.tile.tileSpec)
+                                onResize(FinalResizeOperation(cell.tile.tileSpec, !cell.isIcon))
                                 true
                             }
                         )
@@ -567,24 +591,7 @@
                 )
                 .tileBackground(colors.background)
         ) {
-            val targetValue = if (cell.isIcon) 0f else 1f
-            val animatedProgress = remember { Animatable(targetValue) }
-
-            val resizingState = selectionState.resizingState?.takeIf { selected }
-            LaunchedEffect(targetValue, resizingState) {
-                if (resizingState == null) {
-                    animatedProgress.animateTo(targetValue)
-                } else {
-                    snapshotFlow { resizingState.progression }
-                        .collectLatest { animatedProgress.snapTo(it) }
-                }
-            }
-
-            EditTile(
-                tile = cell.tile,
-                tileWidths = { tileWidths },
-                progress = { animatedProgress.value },
-            )
+            EditTile(tile = cell.tile, state = state, progress = progress)
         }
     }
 }
@@ -651,7 +658,7 @@
 @Composable
 fun EditTile(
     tile: EditTileViewModel,
-    tileWidths: () -> TileWidths?,
+    state: ResizingState,
     progress: () -> Float,
     colors: TileColors = EditModeTileDefaults.editTileColors(),
 ) {
@@ -661,12 +668,16 @@
         verticalAlignment = Alignment.CenterVertically,
         modifier =
             Modifier.layout { measurable, constraints ->
+                    val (min, max) = state.bounds
+                    val currentProgress = progress()
                     // Always display the tile using the large size and trust the parent composable
                     // to clip the content as needed. This stop the labels from being truncated.
-                    val width = tileWidths()?.max ?: constraints.maxWidth
+                    val width =
+                        max?.roundToInt()?.takeIf { it > constraints.maxWidth }
+                            ?: constraints.maxWidth
                     val placeable =
                         measurable.measure(constraints.copy(minWidth = width, maxWidth = width))
-                    val currentProgress = progress()
+
                     val startPadding =
                         if (currentProgress == 0f) {
                             // Find the center of the max width when the tile is icon only
@@ -675,7 +686,7 @@
                             // Find the center of the minimum width to hold the same position as the
                             // tile is resized.
                             val basePadding =
-                                tileWidths()?.min?.let { iconHorizontalCenter(it) } ?: 0f
+                                min?.let { iconHorizontalCenter(it.roundToInt()) } ?: 0f
                             // Large tiles, represented with a progress of 1f, have a 0.dp padding
                             basePadding * (1f - currentProgress)
                         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
index 29ff171..8fd99a5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.qs.panels.ui.compose.bounceableInfo
 import com.android.systemui.qs.panels.ui.compose.rememberEditListState
 import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel
+import com.android.systemui.qs.panels.ui.viewmodel.DetailsViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.IconTilesViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.InfiniteGridViewModel
@@ -49,17 +50,14 @@
 class InfiniteGridLayout
 @Inject
 constructor(
+    private val detailsViewModel: DetailsViewModel,
     private val iconTilesViewModel: IconTilesViewModel,
     private val viewModelFactory: InfiniteGridViewModel.Factory,
     private val tileHapticsViewModelFactoryProvider: TileHapticsViewModelFactoryProvider,
 ) : PaginatableGridLayout {
 
     @Composable
-    override fun SceneScope.TileGrid(
-        tiles: List<TileViewModel>,
-        modifier: Modifier,
-        editModeStart: () -> Unit,
-    ) {
+    override fun SceneScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier) {
         DisposableEffect(tiles) {
             val token = Any()
             tiles.forEach { it.startListening(token) }
@@ -104,6 +102,7 @@
                 tileHapticsViewModelFactoryProvider = tileHapticsViewModelFactoryProvider,
                 coroutineScope = scope,
                 bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns),
+                detailsViewModel = detailsViewModel,
             )
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
index 0a80a19..abdf923 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
@@ -77,10 +77,12 @@
 import com.android.systemui.haptics.msdl.qs.TileHapticsViewModelFactoryProvider
 import com.android.systemui.lifecycle.rememberViewModel
 import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.flags.QsDetailedView
 import com.android.systemui.qs.panels.ui.compose.BounceableInfo
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileHeight
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel
+import com.android.systemui.qs.panels.ui.viewmodel.DetailsViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.TileUiState
 import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.toUiState
@@ -121,6 +123,7 @@
     bounceableInfo: BounceableInfo,
     tileHapticsViewModelFactoryProvider: TileHapticsViewModelFactoryProvider,
     modifier: Modifier = Modifier,
+    detailsViewModel: DetailsViewModel?,
 ) {
     val state by tile.state.collectAsStateWithLifecycle(tile.currentState)
     val currentBounceableInfo by rememberUpdatedState(bounceableInfo)
@@ -163,12 +166,20 @@
                 .takeIf { uiState.handlesLongClick }
         TileContainer(
             onClick = {
-                tile.onClick(expandable)
-                hapticsViewModel?.setTileInteractionState(
-                    TileHapticsViewModel.TileInteractionState.CLICKED
-                )
-                if (uiState.accessibilityUiState.toggleableState != null) {
-                    coroutineScope.launch { currentBounceableInfo.bounceable.animateBounce() }
+                var hasDetails = false
+                if (QsDetailedView.isEnabled) {
+                    hasDetails = detailsViewModel?.onTileClicked(tile.spec) == true
+                }
+                if (!hasDetails) {
+                    // For those tile's who doesn't have a detailed view, process with their
+                    // `onClick` behavior.
+                    tile.onClick(expandable)
+                    hapticsViewModel?.setTileInteractionState(
+                        TileHapticsViewModel.TileInteractionState.CLICKED
+                    )
+                    if (uiState.accessibilityUiState.toggleableState != null) {
+                        coroutineScope.launch { currentBounceableInfo.bounceable.animateBounce() }
+                    }
                 }
             },
             onLongClick = longClick,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt
index 1d36aee..c6c6dca 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt
@@ -27,11 +27,8 @@
 
 /** Creates the state of the current selected tile that is remembered across compositions. */
 @Composable
-fun rememberSelectionState(
-    onResize: (TileSpec) -> Unit,
-    onResizeEnd: (TileSpec) -> Unit,
-): MutableSelectionState {
-    return remember { MutableSelectionState(onResize, onResizeEnd) }
+fun rememberSelectionState(): MutableSelectionState {
+    return remember { MutableSelectionState() }
 }
 
 /**
@@ -41,47 +38,18 @@
 data class Selection(val tileSpec: TileSpec, val manual: Boolean)
 
 /** Holds the state of the current selection. */
-class MutableSelectionState(
-    val onResize: (TileSpec) -> Unit,
-    private val onResizeEnd: (TileSpec) -> Unit,
-) {
+class MutableSelectionState {
     private var _selection = mutableStateOf<Selection?>(null)
-    private var _resizingState = mutableStateOf<ResizingState?>(null)
 
     /** The [Selection] if a tile is selected, null if not. */
     val selection by _selection
 
-    /** The [ResizingState] of the selected tile is currently being resized, null if not. */
-    val resizingState by _resizingState
-
     fun select(tileSpec: TileSpec, manual: Boolean) {
         _selection.value = Selection(tileSpec, manual)
     }
 
     fun unSelect() {
         _selection.value = null
-        onResizingDragEnd()
-    }
-
-    fun onResizingDrag(offset: Float) {
-        _resizingState.value?.onDrag(offset)
-    }
-
-    fun onResizingDragStart(tileWidths: TileWidths) {
-        _selection.value?.let {
-            _resizingState.value = ResizingState(tileWidths) { onResize(it.tileSpec) }
-        }
-    }
-
-    fun onResizingDragEnd() {
-        _resizingState.value = null
-        _selection.value?.let {
-            onResizeEnd(it.tileSpec)
-
-            // Mark the selection as automatic in case the tile ends up moving to a different
-            // row with its new size.
-            _selection.value = it.copy(manual = false)
-        }
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingState.kt
index 41c3de5..1113053 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingState.kt
@@ -16,56 +16,82 @@
 
 package com.android.systemui.qs.panels.ui.compose.selection
 
+import androidx.compose.foundation.gestures.AnchoredDraggableState
+import androidx.compose.foundation.gestures.DraggableAnchors
+import androidx.compose.foundation.gestures.animateTo
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableFloatStateOf
-import androidx.compose.runtime.mutableIntStateOf
-import androidx.compose.runtime.setValue
-import com.android.systemui.qs.panels.ui.compose.selection.ResizingDefaults.RESIZING_THRESHOLD
+import androidx.compose.runtime.remember
+import com.android.systemui.qs.panels.ui.compose.selection.ResizingState.ResizeOperation.FinalResizeOperation
+import com.android.systemui.qs.panels.ui.compose.selection.ResizingState.ResizeOperation.TemporaryResizeOperation
+import com.android.systemui.qs.pipeline.shared.TileSpec
 
-class ResizingState(val widths: TileWidths, private val onResize: () -> Unit) {
-    /** Total drag offset of this resize operation. */
-    private var totalOffset by mutableFloatStateOf(0f)
+@Composable
+fun rememberResizingState(tileSpec: TileSpec, startsAsIcon: Boolean): ResizingState {
+    return remember(tileSpec) { ResizingState(tileSpec, startsAsIcon) }
+}
 
-    /** Width in pixels of the resizing tile. */
-    var width by mutableIntStateOf(widths.base)
+enum class QSDragAnchor {
+    Icon,
+    Large,
+}
 
-    /** Progression between icon (0) and large (1) sizes. */
-    val progression
-        get() = calculateProgression()
+class ResizingState(tileSpec: TileSpec, startsAsIcon: Boolean) {
+    val anchoredDraggableState =
+        AnchoredDraggableState(if (startsAsIcon) QSDragAnchor.Icon else QSDragAnchor.Large)
 
-    // Whether the tile is currently over the threshold and should be a large tile
-    private var passedThreshold: Boolean = passedThreshold(progression)
+    val bounds by derivedStateOf {
+        anchoredDraggableState.anchors.minPosition().takeIf { !it.isNaN() } to
+            anchoredDraggableState.anchors.maxPosition().takeIf { !it.isNaN() }
+    }
 
-    fun onDrag(offset: Float) {
-        totalOffset += offset
-        width = (widths.base + totalOffset).toInt().coerceIn(widths.min, widths.max)
+    val temporaryResizeOperation by derivedStateOf {
+        TemporaryResizeOperation(
+            tileSpec,
+            toIcon = anchoredDraggableState.currentValue == QSDragAnchor.Icon,
+        )
+    }
 
-        passedThreshold(progression).let {
-            // Resize if we went over the threshold
-            if (passedThreshold != it) {
-                passedThreshold = it
-                onResize()
+    val finalResizeOperation by derivedStateOf {
+        FinalResizeOperation(
+            tileSpec,
+            toIcon = anchoredDraggableState.settledValue == QSDragAnchor.Icon,
+        )
+    }
+
+    fun updateAnchors(min: Float, max: Float) {
+        anchoredDraggableState.updateAnchors(
+            DraggableAnchors {
+                QSDragAnchor.Icon at min
+                QSDragAnchor.Large at max
             }
-        }
+        )
     }
 
-    private fun passedThreshold(progression: Float): Boolean {
-        return progression >= RESIZING_THRESHOLD
+    suspend fun updateCurrentValue(isIcon: Boolean) {
+        anchoredDraggableState.animateTo(if (isIcon) QSDragAnchor.Icon else QSDragAnchor.Large)
     }
 
-    /** The progression of the resizing tile between an icon tile (0f) and a large tile (1f) */
-    private fun calculateProgression(): Float {
-        return ((width - widths.min) / (widths.max - widths.min).toFloat()).coerceIn(0f, 1f)
+    suspend fun toggleCurrentValue() {
+        val isIcon = anchoredDraggableState.currentValue == QSDragAnchor.Icon
+        updateCurrentValue(!isIcon)
     }
-}
 
-/** Holds the width of a tile as well as its min and max widths */
-data class TileWidths(val base: Int, val min: Int, val max: Int) {
-    init {
-        check(max > min) { "The max width needs to be larger than the min width." }
+    fun progress(): Float = anchoredDraggableState.progress(QSDragAnchor.Icon, QSDragAnchor.Large)
+
+    /**
+     * Represents a resizing operation for a tile.
+     *
+     * @property spec The tile's [TileSpec]
+     * @property toIcon The new size for the tile.
+     */
+    sealed class ResizeOperation private constructor(val spec: TileSpec, val toIcon: Boolean) {
+        /** A temporary resizing operation, used while a resizing movement is in motion. */
+        class TemporaryResizeOperation(spec: TileSpec, toIcon: Boolean) :
+            ResizeOperation(spec, toIcon)
+
+        /** A final resizing operation, used while a resizing movement is done. */
+        class FinalResizeOperation(spec: TileSpec, toIcon: Boolean) : ResizeOperation(spec, toIcon)
     }
 }
-
-private object ResizingDefaults {
-    const val RESIZING_THRESHOLD = .25f
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
index 8a345ce..c1545e1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
@@ -19,10 +19,11 @@
 import androidx.compose.animation.core.Spring
 import androidx.compose.animation.core.animateDpAsState
 import androidx.compose.animation.core.animateFloatAsState
-import androidx.compose.animation.core.animateIntAsState
 import androidx.compose.animation.core.spring
 import androidx.compose.foundation.Canvas
-import androidx.compose.foundation.gestures.detectHorizontalDragGestures
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.anchoredDraggable
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.foundation.layout.size
@@ -30,7 +31,9 @@
 import androidx.compose.material3.LocalMinimumInteractiveComponentSize
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.drawWithContent
@@ -40,16 +43,16 @@
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.SolidColor
 import androidx.compose.ui.graphics.drawscope.Stroke
-import androidx.compose.ui.input.pointer.pointerInput
 import androidx.compose.ui.layout.layout
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.toSize
 import androidx.compose.ui.zIndex
-import com.android.compose.modifiers.thenIf
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius
 import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.ResizingDotSize
 import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.SelectedBorderWidth
+import kotlin.math.roundToInt
+import kotlinx.coroutines.launch
 
 /**
  * Places a dot to handle resizing drag events. Use this on tiles to resize.
@@ -58,31 +61,24 @@
  * selected.
  *
  * @param selected whether resizing drag events should be handled
- * @param selectionState the [MutableSelectionState] on the grid
+ * @param state the [ResizingState] for the tile
  * @param selectionAlpha the animated value for the dot and border alpha
  * @param selectionColor the [Color] of the dot and border
- * @param tileWidths the [TileWidths] of the selected tile
  */
 @Composable
 fun ResizableTileContainer(
     selected: Boolean,
-    selectionState: MutableSelectionState,
+    state: ResizingState,
     selectionAlpha: () -> Float,
     selectionColor: Color,
-    tileWidths: () -> TileWidths?,
     modifier: Modifier = Modifier,
     content: @Composable BoxScope.() -> Unit = {},
 ) {
-    Box(
-        modifier
-            .resizable(selected, selectionState, tileWidths)
-            .selectionBorder(selectionColor, selectionAlpha)
-    ) {
+    Box(modifier.resizable(selected, state).selectionBorder(selectionColor, selectionAlpha)) {
         content()
         ResizingHandle(
             enabled = selected,
-            selectionState = selectionState,
-            tileWidths = tileWidths,
+            state = state,
             modifier =
                 // Higher zIndex to make sure the handle is drawn above the content
                 Modifier.zIndex(2f),
@@ -91,15 +87,11 @@
 }
 
 @Composable
-private fun ResizingHandle(
-    enabled: Boolean,
-    selectionState: MutableSelectionState,
-    tileWidths: () -> TileWidths?,
-    modifier: Modifier = Modifier,
-) {
+private fun ResizingHandle(enabled: Boolean, state: ResizingState, modifier: Modifier = Modifier) {
     // Manually creating the touch target around the resizing dot to ensure that the next tile
     // does not receive the touch input accidentally.
     val minTouchTargetSize = LocalMinimumInteractiveComponentSize.current
+    val scope = rememberCoroutineScope()
     Box(
         modifier
             .layout { measurable, constraints ->
@@ -112,20 +104,14 @@
                     )
                 }
             }
-            .thenIf(enabled) {
-                Modifier.systemGestureExclusion { Rect(Offset.Zero, it.size.toSize()) }
-                    .pointerInput(Unit) {
-                        detectHorizontalDragGestures(
-                            onHorizontalDrag = { _, offset ->
-                                selectionState.onResizingDrag(offset)
-                            },
-                            onDragStart = {
-                                tileWidths()?.let { selectionState.onResizingDragStart(it) }
-                            },
-                            onDragEnd = selectionState::onResizingDragEnd,
-                            onDragCancel = selectionState::onResizingDragEnd,
-                        )
-                    }
+            .systemGestureExclusion { Rect(Offset.Zero, it.size.toSize()) }
+            .anchoredDraggable(
+                enabled = enabled,
+                state = state.anchoredDraggableState,
+                orientation = Orientation.Horizontal,
+            )
+            .clickable(enabled = enabled, interactionSource = null, indication = null) {
+                scope.launch { state.toggleCurrentValue() }
             }
     ) {
         ResizingDot(enabled = enabled, modifier = Modifier.align(Alignment.Center))
@@ -165,23 +151,15 @@
 }
 
 @Composable
-private fun Modifier.resizable(
-    selected: Boolean,
-    selectionState: MutableSelectionState,
-    tileWidths: () -> TileWidths?,
-): Modifier {
+private fun Modifier.resizable(selected: Boolean, state: ResizingState): Modifier {
     if (!selected) return zIndex(1f)
 
-    // Animated diff between the current width and the resized width of the tile. We can't use
-    // animateContentSize here as the tile is sometimes unbounded.
-    val remainingOffset by
-        animateIntAsState(
-            selectionState.resizingState?.let { tileWidths()?.base?.minus(it.width) ?: 0 } ?: 0,
-            label = "QSEditTileWidthOffset",
-        )
     return zIndex(2f).layout { measurable, constraints ->
+        val isIdle by derivedStateOf { state.progress().let { it == 0f || it == 1f } }
         // Grab the width from the resizing state if a resize is in progress
-        val width = selectionState.resizingState?.width ?: (constraints.maxWidth - remainingOffset)
+        val width =
+            state.anchoredDraggableState.requireOffset().roundToInt().takeIf { !isIdle }
+                ?: constraints.maxWidth
         val placeable = measurable.measure(constraints.copy(minWidth = width, maxWidth = width))
         layout(constraints.maxWidth, placeable.height) { placeable.place(0, 0) }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModel.kt
new file mode 100644
index 0000000..d8361f5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModel.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.qs.panels.ui.viewmodel
+
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.qs.TileDetailsViewModel
+import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import javax.inject.Inject
+import kotlinx.coroutines.flow.StateFlow
+
+@SysUISingleton
+class DetailsViewModel
+@Inject constructor(val currentTilesInteractor: CurrentTilesInteractor) {
+
+    /**
+     * The current active [TileDetailsViewModel]. If it's `null`, it means the qs overlay is not
+     * showing any details view. It changes when [onTileClicked] and [closeDetailedView].
+     */
+    private val _activeTileDetails = mutableStateOf<TileDetailsViewModel?>(null)
+    val activeTileDetails by _activeTileDetails
+
+    /**
+     * Update the active [TileDetailsViewModel] to `null`.
+     * @see activeTileDetails
+     */
+    fun closeDetailedView() {
+        _activeTileDetails.value = null
+    }
+
+    /**
+     * Update the active [TileDetailsViewModel] to the `spec`'s corresponding view model.
+     * Return if the [TileDetailsViewModel] is successfully found.
+     * @see activeTileDetails
+     */
+    fun onTileClicked(spec: TileSpec?): Boolean {
+        if (spec == null) {
+            _activeTileDetails.value = null
+            return false
+        }
+
+        _activeTileDetails.value = currentTilesInteractor
+            .currentQSTiles
+            .firstOrNull { it.tileSpec == spec.spec }
+            ?.detailsViewModel
+
+        return _activeTileDetails.value != null
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModel.kt
new file mode 100644
index 0000000..b033473
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModel.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.qs.panels.ui.viewmodel
+
+import com.android.systemui.classifier.domain.interactor.FalsingInteractor
+import com.android.systemui.plugins.FalsingManager
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+class EditModeButtonViewModel
+@AssistedInject
+constructor(
+    private val editModeViewModel: EditModeViewModel,
+    private val falsingInteractor: FalsingInteractor,
+) {
+
+    fun onButtonClick() {
+        if (!falsingInteractor.isFalseTap(FalsingManager.LOW_PENALTY)) {
+            editModeViewModel.startEditing()
+        }
+    }
+
+    @AssistedFactory
+    interface Factory {
+        fun create(): EditModeButtonViewModel
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt
index bff330b..4a18872 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt
@@ -17,6 +17,8 @@
 package com.android.systemui.qs.panels.ui.viewmodel
 
 import androidx.compose.runtime.getValue
+import com.android.systemui.classifier.Classifier.QS_SWIPE_SIDE
+import com.android.systemui.classifier.domain.interactor.FalsingInteractor
 import com.android.systemui.development.ui.viewmodel.BuildNumberViewModel
 import com.android.systemui.lifecycle.ExclusiveActivatable
 import com.android.systemui.lifecycle.Hydrator
@@ -36,6 +38,8 @@
     paginatedGridInteractor: PaginatedGridInteractor,
     inFirstPageViewModel: InFirstPageViewModel,
     val buildNumberViewModelFactory: BuildNumberViewModel.Factory,
+    val editModeButtonViewModelFactory: EditModeButtonViewModel.Factory,
+    private val falsingInteractor: FalsingInteractor,
 ) : IconTilesViewModel by iconTilesViewModel, ExclusiveActivatable() {
 
     private val hydrator = Hydrator("PaginatedGridViewModel")
@@ -53,6 +57,10 @@
     val columns: Int
         get() = columnsWithMediaViewModel.columns
 
+    fun registerSideSwipeGesture() {
+        falsingInteractor.isFalseTouch(QS_SWIPE_SIDE)
+    }
+
     override suspend fun onActivated(): Nothing {
         coroutineScope {
             launch { hydrator.activate() }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 1fb76f1..b7ebce2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -27,6 +27,7 @@
 import android.graphics.Color
 import android.graphics.PorterDuff
 import android.graphics.Rect
+import android.graphics.Typeface
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.GradientDrawable
 import android.graphics.drawable.LayerDrawable
@@ -308,6 +309,14 @@
         }
         setLabelColor(getLabelColorForState(QSTile.State.DEFAULT_STATE))
         setSecondaryLabelColor(getSecondaryLabelColorForState(QSTile.State.DEFAULT_STATE))
+
+        if (Flags.gsfQuickSettings()) {
+            label.apply {
+                typeface = Typeface.create("gsf-title-small-emphasized", Typeface.NORMAL)
+            }
+            secondaryLabel.apply { typeface = Typeface.create("gsf-label-medium", Typeface.NORMAL) }
+        }
+
         addView(labelContainer)
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
index 42ef0cd..7225800 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
@@ -28,11 +28,14 @@
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.plugins.qs.TileDetailsViewModel
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.qs.QSHost
 import com.android.systemui.qs.QsEventLogger
+import com.android.systemui.qs.flags.QsDetailedView
 import com.android.systemui.qs.logging.QSLogger
 import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.qs.tiles.dialog.InternetDetailsViewModel
 import com.android.systemui.qs.tiles.dialog.InternetDialogManager
 import com.android.systemui.qs.tiles.dialog.WifiStateWorker
 import com.android.systemui.res.R
@@ -90,6 +93,9 @@
     }
 
     override fun handleClick(expandable: Expandable?) {
+        if (QsDetailedView.isEnabled) {
+            return
+        }
         mainHandler.post {
             internetDialogManager.create(
                 aboveStatusBar = true,
@@ -100,6 +106,10 @@
         }
     }
 
+    override fun getDetailsViewModel(): TileDetailsViewModel {
+        return InternetDetailsViewModel { longClick(null) }
+    }
+
     override fun secondaryClick(expandable: Expandable?) {
         // TODO(b/358352265): Figure out the correct action for the secondary click
         // Toggle wifi
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailedViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailedViewModel.kt
new file mode 100644
index 0000000..f239a17
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailedViewModel.kt
@@ -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.systemui.qs.tiles.dialog
+
+import android.view.LayoutInflater
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.viewinterop.AndroidView
+import com.android.systemui.plugins.qs.TileDetailsViewModel
+import com.android.systemui.res.R
+
+class InternetDetailsViewModel(
+    onLongClick: () -> Unit,
+) : TileDetailsViewModel() {
+    private val _onLongClick = onLongClick
+
+    @Composable
+    override fun GetContentView() {
+        AndroidView(
+            modifier = Modifier.fillMaxWidth().fillMaxHeight(),
+            factory = { context ->
+                // Inflate with the existing dialog xml layout
+                LayoutInflater.from(context)
+                    .inflate(R.layout.internet_connectivity_dialog, null)
+                // TODO: b/377388104 - Implement the internet details view
+            },
+        )
+    }
+
+    override fun clickOnSettingsButton() {
+        _onLongClick()
+    }
+
+    override fun getTitle(): String {
+        // TODO: b/377388104 Update the placeholder text
+        return "Internet"
+    }
+
+    override fun getSubTitle(): String {
+        // TODO: b/377388104 Update the placeholder text
+        return "Tab a network to connect"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt
index da175c9..62b1203 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt
@@ -18,6 +18,7 @@
 
 import com.android.systemui.brightness.ui.viewmodel.BrightnessSliderViewModel
 import com.android.systemui.lifecycle.ExclusiveActivatable
+import com.android.systemui.qs.panels.ui.viewmodel.DetailsViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.EditModeViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.QuickQuickSettingsViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.TileGridViewModel
@@ -36,6 +37,7 @@
     @Assisted supportsBrightnessMirroring: Boolean,
     val tileGridViewModel: TileGridViewModel,
     val editModeViewModel: EditModeViewModel,
+    val detailsViewModel: DetailsViewModel,
 ) : ExclusiveActivatable() {
 
     val brightnessSliderViewModel =
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
index 02b2bb1..d94f00f 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
@@ -171,9 +171,16 @@
             }
         ALL_ISSUE_TYPES.keys.forEach {
             popupMenu.menu.add(it).apply {
+                // Set this for every item in the list to ensure equal spacing. Set it to
+                // transparent for non-selected items so icon is only visible for selected element.
                 setIcon(R.drawable.arrow_pointing_down)
                 if (it != state.issueTypeRes) {
                     iconTintList = ColorStateList.valueOf(Color.TRANSPARENT)
+                } else {
+                    contentDescription =
+                        context.getString(com.android.internal.R.string.selected) +
+                            " " +
+                            context.getString(it)
                 }
                 intent = Intent().putExtra(EXTRA_ISSUE_TYPE_RES, it)
 
diff --git a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
index e441a23..e36e40d 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.scene.shared.model.Overlays
 import com.android.systemui.scene.shared.model.SceneContainerConfig
 import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.ui.composable.SceneContainerTransitions
 import com.android.systemui.scene.ui.viewmodel.SplitEdgeDetector
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.shade.shared.flag.DualShade
@@ -98,6 +99,7 @@
                         Scenes.Shade.takeUnless { DualShade.isEnabled },
                     ),
                 initialSceneKey = Scenes.Gone,
+                transitions = SceneContainerTransitions,
                 overlayKeys =
                     listOfNotNull(
                         Overlays.NotificationsShade.takeIf { DualShade.isEnabled },
diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
index 4beec10..fe01452 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.scene.shared.model.Overlays
 import com.android.systemui.scene.shared.model.SceneContainerConfig
 import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.ui.composable.SceneContainerTransitions
 import com.android.systemui.scene.ui.viewmodel.SplitEdgeDetector
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.shade.shared.flag.DualShade
@@ -106,6 +107,7 @@
                         Scenes.Shade.takeUnless { DualShade.isEnabled },
                     ),
                 initialSceneKey = Scenes.Lockscreen,
+                transitions = SceneContainerTransitions,
                 overlayKeys =
                     listOfNotNull(
                         Overlays.NotificationsShade.takeIf { DualShade.isEnabled },
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt
index 16ed59f4..c1646b8 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.scene.domain.resolver.HomeSceneFamilyResolverModule
 import com.android.systemui.scene.shared.model.SceneContainerConfig
 import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.ui.composable.SceneContainerTransitions
 import dagger.Module
 import dagger.Provides
 
@@ -35,7 +36,7 @@
 
             // List SceneResolver modules for supported SceneFamilies
             HomeSceneFamilyResolverModule::class,
-        ],
+        ]
 )
 object ShadelessSceneContainerFrameworkModule {
 
@@ -46,20 +47,12 @@
         return SceneContainerConfig(
             // Note that this list is in z-order. The first one is the bottom-most and the
             // last one is top-most.
-            sceneKeys =
-                listOf(
-                    Scenes.Gone,
-                    Scenes.Lockscreen,
-                    Scenes.Bouncer,
-                ),
+            sceneKeys = listOf(Scenes.Gone, Scenes.Lockscreen, Scenes.Bouncer),
             initialSceneKey = Scenes.Lockscreen,
+            transitions = SceneContainerTransitions,
             overlayKeys = emptyList(),
             navigationDistances =
-                mapOf(
-                    Scenes.Gone to 0,
-                    Scenes.Lockscreen to 0,
-                    Scenes.Bouncer to 1,
-                )
+                mapOf(Scenes.Gone to 0, Scenes.Lockscreen to 0, Scenes.Bouncer to 1),
         )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractor.kt
new file mode 100644
index 0000000..d7c3b6b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractor.kt
@@ -0,0 +1,93 @@
+/*
+ * 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.domain.interactor
+
+import com.android.compose.animation.scene.ContentKey
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
+import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+
+class DisabledContentInteractor
+@Inject
+constructor(private val disableFlagsInteractor: DisableFlagsInteractor) {
+
+    /** Returns `true` if the given [key] is disabled; `false` if it's enabled */
+    fun isDisabled(
+        key: ContentKey,
+        disabledFlags: DisableFlagsModel = disableFlagsInteractor.disableFlags.value,
+    ): Boolean {
+        return with(disabledFlags) {
+            when (key) {
+                Scenes.Shade,
+                Overlays.NotificationsShade -> !isShadeEnabled()
+                Scenes.QuickSettings,
+                Overlays.QuickSettingsShade -> !isQuickSettingsEnabled()
+                else -> false
+            }
+        }
+    }
+
+    /** Runs the given [block] each time that [key] becomes disabled. */
+    suspend fun repeatWhenDisabled(key: ContentKey, block: suspend (disabled: ContentKey) -> Unit) {
+        disableFlagsInteractor.disableFlags
+            .map { isDisabled(key) }
+            .distinctUntilChanged()
+            .collectLatest { isDisabled ->
+                if (isDisabled) {
+                    block(key)
+                }
+            }
+    }
+
+    /**
+     * Returns a filtered version of [unfiltered], without action-result entries that would navigate
+     * to disabled scenes.
+     */
+    fun filteredUserActions(
+        unfiltered: Flow<Map<UserAction, UserActionResult>>
+    ): Flow<Map<UserAction, UserActionResult>> {
+        return combine(disableFlagsInteractor.disableFlags, unfiltered) {
+            disabledFlags,
+            unfilteredMap ->
+            unfilteredMap.filterValues { actionResult ->
+                val destination =
+                    when (actionResult) {
+                        is UserActionResult.ChangeScene -> actionResult.toScene
+                        is UserActionResult.ShowOverlay -> actionResult.overlay
+                        is UserActionResult.ReplaceByOverlay -> actionResult.overlay
+                        else -> null
+                    }
+                if (destination != null) {
+                    // results that lead to a disabled destination get filtered out.
+                    !isDisabled(key = destination, disabledFlags = disabledFlags)
+                } else {
+                    // Action results that don't lead to a destination are never filtered out.
+                    true
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index f20e5a5..d83d74e 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -21,6 +21,8 @@
 import com.android.compose.animation.scene.OverlayKey
 import com.android.compose.animation.scene.SceneKey
 import com.android.compose.animation.scene.TransitionKey
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
@@ -64,6 +66,7 @@
     private val sceneFamilyResolvers: Lazy<Map<SceneKey, @JvmSuppressWildcards SceneResolver>>,
     private val deviceUnlockedInteractor: Lazy<DeviceUnlockedInteractor>,
     private val keyguardEnabledInteractor: Lazy<KeyguardEnabledInteractor>,
+    private val disabledContentInteractor: DisabledContentInteractor,
 ) {
 
     interface OnSceneAboutToChangeListener {
@@ -465,6 +468,10 @@
             return false
         }
 
+        if (disabledContentInteractor.isDisabled(to)) {
+            return false
+        }
+
         val inMidTransitionFromGone =
             (transitionState.value as? ObservableTransitionState.Transition)?.fromContent ==
                 Scenes.Gone
@@ -503,6 +510,10 @@
                 " Logging reason for overlay change was: $loggingReason"
         }
 
+        if (to != null && disabledContentInteractor.isDisabled(to)) {
+            return false
+        }
+
         val isFromValid = (from == null) || (from in currentOverlays.value)
         val isToValid =
             (to == null) || (to !in currentOverlays.value && to in repository.allContentKeys)
@@ -517,4 +528,14 @@
     /** Returns `true` if [scene] can be resolved from [family]. */
     fun isSceneInFamily(scene: SceneKey, family: SceneKey): Boolean =
         sceneFamilyResolvers.get()[family]?.includesScene(scene) == true
+
+    /**
+     * Returns a filtered version of [unfiltered], without action-result entries that would navigate
+     * to disabled scenes.
+     */
+    fun filteredUserActions(
+        unfiltered: Flow<Map<UserAction, UserActionResult>>
+    ): Flow<Map<UserAction, UserActionResult>> {
+        return disabledContentInteractor.filteredUserActions(unfiltered)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt
index ba789a0..3a07ce9 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.scene.domain.interactor
 
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
@@ -29,9 +30,9 @@
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.statusbar.NotificationPresenter
 import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.notification.init.NotificationsController
 import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import javax.inject.Inject
 import javax.inject.Provider
 import kotlinx.coroutines.CoroutineScope
@@ -44,7 +45,6 @@
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 /** Business logic about the visibility of various parts of the window root view. */
 @OptIn(ExperimentalCoroutinesApi::class)
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index aece5c6..8d8c24e 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -19,7 +19,6 @@
 package com.android.systemui.scene.domain.startable
 
 import android.app.StatusBarManager
-import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.compose.animation.scene.SceneKey
 import com.android.internal.logging.UiEventLogger
@@ -56,6 +55,7 @@
 import com.android.systemui.power.shared.model.WakeSleepReason
 import com.android.systemui.scene.data.model.asIterable
 import com.android.systemui.scene.data.model.sceneStackOf
+import com.android.systemui.scene.domain.interactor.DisabledContentInteractor
 import com.android.systemui.scene.domain.interactor.SceneBackInteractor
 import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
 import com.android.systemui.scene.domain.interactor.SceneInteractor
@@ -103,6 +103,7 @@
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.mapNotNull
 import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
 
 /**
  * Hooks up business logic that manipulates the state of the [SceneInteractor] for the system UI
@@ -144,6 +145,7 @@
     private val alternateBouncerInteractor: AlternateBouncerInteractor,
     private val vibratorHelper: VibratorHelper,
     private val msdlPlayer: MSDLPlayer,
+    private val disabledContentInteractor: DisabledContentInteractor,
 ) : CoreStartable {
     private val centralSurfaces: CentralSurfaces?
         get() = centralSurfacesOptLazy.get().getOrNull()
@@ -281,6 +283,7 @@
         handlePowerState()
         handleDreamState()
         handleShadeTouchability()
+        handleDisableFlags()
     }
 
     private fun handleBouncerImeVisibility() {
@@ -565,6 +568,38 @@
         }
     }
 
+    private fun handleDisableFlags() {
+        applicationScope.launch {
+            launch {
+                sceneInteractor.currentScene.collectLatest { currentScene ->
+                    disabledContentInteractor.repeatWhenDisabled(currentScene) {
+                        switchToScene(
+                            targetSceneKey = SceneFamilies.Home,
+                            loggingReason =
+                                "Current scene ${currentScene.debugName} became" + " disabled",
+                        )
+                    }
+                }
+            }
+
+            launch {
+                sceneInteractor.currentOverlays.collectLatest { overlays ->
+                    overlays.forEach { overlay ->
+                        launch {
+                            disabledContentInteractor.repeatWhenDisabled(overlay) {
+                                sceneInteractor.hideOverlay(
+                                    overlay = overlay,
+                                    loggingReason =
+                                        "Overlay ${overlay.debugName} became" + " disabled",
+                                )
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     private fun handleDeviceEntryHapticsWhileDeviceLocked() {
         applicationScope.launch {
             deviceEntryInteractor.isDeviceEntered.collectLatest { isDeviceEntered ->
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt
index 2311e47..ce7be83 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt
@@ -18,6 +18,7 @@
 
 import com.android.compose.animation.scene.OverlayKey
 import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.SceneTransitions
 
 /** Models the configuration of the scene container. */
 data class SceneContainerConfig(
@@ -38,6 +39,9 @@
      */
     val initialSceneKey: SceneKey,
 
+    /** Transition definitions to be used when animating between scene transitions. */
+    val transitions: SceneTransitions,
+
     /**
      * The keys to all overlays in the container, sorted by z-order such that the last one renders
      * on top of all previous ones. Overlay keys within the same container must not repeat but it's
@@ -61,7 +65,7 @@
      * Note that this is not the z-order of rendering; that's determined by the order of declaration
      * of scenes in the [sceneKeys] list.
      */
-    val navigationDistances: Map<SceneKey, Int>
+    val navigationDistances: Map<SceneKey, Int>,
 ) {
     init {
         check(sceneKeys.isNotEmpty()) { "A container must have at least one scene key." }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
index 1e3a233..1c15c74 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
@@ -196,6 +196,7 @@
                             sceneByKey = sceneByKey,
                             overlayByKey = overlayByKey,
                             initialSceneKey = containerConfig.initialSceneKey,
+                            sceneTransitions = containerConfig.transitions,
                             dataSourceDelegator = dataSourceDelegator,
                             qsSceneAdapter = qsSceneAdapter,
                         )
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
index 32d5cb4..c1e8032 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
@@ -280,6 +280,16 @@
         }
     }
 
+    /**
+     * Returns a filtered version of [unfiltered], without action-result entries that would navigate
+     * to disabled scenes.
+     */
+    fun filteredUserActions(
+        unfiltered: Flow<Map<UserAction, UserActionResult>>
+    ): Flow<Map<UserAction, UserActionResult>> {
+        return sceneInteractor.filteredUserActions(unfiltered)
+    }
+
     /** Defines interface for classes that can handle externally-reported [MotionEvent]s. */
     interface MotionEventHandler {
         /** Notifies that a [MotionEvent] has occurred. */
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt
index b8ea8f9..c5c705c 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt
@@ -29,6 +29,7 @@
 import android.view.ViewGroup
 import android.view.WindowInsets
 import android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL
+import android.view.accessibility.AccessibilityEvent
 import android.widget.FrameLayout
 import android.widget.ImageView
 import com.android.systemui.res.R
@@ -83,6 +84,20 @@
         })
 
         gestureDetector.setIsLongpressEnabled(false)
+
+        // Extend the timeout on any accessibility event (e.g. voice access or explore-by-touch).
+        setAccessibilityDelegate(
+            object : AccessibilityDelegate() {
+                override fun onRequestSendAccessibilityEvent(
+                    host: ViewGroup,
+                    child: View,
+                    event: AccessibilityEvent,
+                ): Boolean {
+                    userInteractionCallback?.invoke()
+                    return super.onRequestSendAccessibilityEvent(host, child, event)
+                }
+            }
+        )
     }
 
     override fun onFinishInflate() {
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
index 8c004c4..6844f05 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
@@ -48,7 +48,7 @@
 import com.android.systemui.brightness.ui.viewmodel.BrightnessSliderViewModel;
 import com.android.systemui.compose.ComposeInitializer;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.qs.flags.QSComposeFragment;
+import com.android.systemui.qs.flags.QsInCompose;
 import com.android.systemui.res.R;
 import com.android.systemui.shade.domain.interactor.ShadeInteractor;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
@@ -96,7 +96,7 @@
         super.onCreate(savedInstanceState);
         setWindowAttributes();
         View view;
-        if (!QSComposeFragment.isEnabled()) {
+        if (!QsInCompose.isEnabled()) {
             setContentView(R.layout.brightness_mirror_container);
             view = findViewById(R.id.brightness_mirror_container);
             setDialogContent((FrameLayout) view);
@@ -140,7 +140,7 @@
         window.getDecorView();
         window.setLayout(WRAP_CONTENT, WRAP_CONTENT);
         getTheme().applyStyle(R.style.Theme_SystemUI_QuickSettings, false);
-        if (QSComposeFragment.isEnabled()) {
+        if (QsInCompose.isEnabled()) {
             window.getDecorView().addOnAttachStateChangeListener(
                     new View.OnAttachStateChangeListener() {
                         @Override
@@ -217,7 +217,7 @@
     @Override
     protected void onStart() {
         super.onStart();
-        if (!QSComposeFragment.isEnabled()) {
+        if (!QsInCompose.isEnabled()) {
             mBrightnessController.registerCallbacks();
         }
         MetricsLogger.visible(this, MetricsEvent.BRIGHTNESS_DIALOG);
@@ -241,7 +241,7 @@
     protected void onStop() {
         super.onStop();
         MetricsLogger.hidden(this, MetricsEvent.BRIGHTNESS_DIALOG);
-        if (!QSComposeFragment.isEnabled()) {
+        if (!QsInCompose.isEnabled()) {
             mBrightnessController.unregisterCallbacks();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
index 49ceba8..31780a5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
@@ -37,9 +37,11 @@
 import androidx.lifecycle.LifecycleRegistry
 import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.compose.theme.PlatformTheme
 import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.Flags
+import com.android.systemui.Flags.communalHubOnMobile
 import com.android.systemui.ambient.touch.TouchMonitor
 import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent
 import com.android.systemui.communal.dagger.Communal
@@ -70,7 +72,6 @@
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 /**
  * Controller that's responsible for the glanceable hub container view and its touch handling.
@@ -513,14 +514,19 @@
         val touchOnUmo = keyguardMediaController.isWithinMediaViewBounds(ev.x.toInt(), ev.y.toInt())
         val touchOnSmartspace =
             lockscreenSmartspaceController.isWithinSmartspaceBounds(ev.x.toInt(), ev.y.toInt())
-        if (!hubShowing && (touchOnNotifications || touchOnUmo || touchOnSmartspace)) {
+        val glanceableHubV2 = communalHubOnMobile()
+        if (
+            !hubShowing &&
+                (touchOnNotifications || touchOnUmo || touchOnSmartspace || glanceableHubV2)
+        ) {
             logger.d({
                 "Lockscreen touch ignored: touchOnNotifications: $bool1, touchOnUmo: $bool2, " +
-                    "touchOnSmartspace: $bool3"
+                    "touchOnSmartspace: $bool3, glanceableHubV2: $bool4"
             }) {
                 bool1 = touchOnNotifications
                 bool2 = touchOnUmo
                 bool3 = touchOnSmartspace
+                bool4 = glanceableHubV2
             }
             return false
         }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 42a756c..88522d5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -186,13 +186,15 @@
 import com.android.systemui.statusbar.notification.AnimatableProperty;
 import com.android.systemui.statusbar.notification.ConversationNotificationManager;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.PropertyAnimator;
 import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor;
 import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -217,17 +219,15 @@
 import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.ShadeTouchableRegionManager;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
 import com.android.systemui.statusbar.phone.TapAgainViewController;
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView;
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.policy.SplitShadeStateController;
 import com.android.systemui.unfold.SysUIUnfoldComponent;
 import com.android.systemui.util.Compile;
@@ -298,7 +298,7 @@
      * The minimum scale to "squish" the Shade and associated elements down to, for Back gesture
      */
     public static final float SHADE_BACK_ANIM_MIN_SCALE = 0.9f;
-    private final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
+    private final ShadeTouchableRegionManager mShadeTouchableRegionManager;
     private final Resources mResources;
     private final KeyguardStateController mKeyguardStateController;
     private final SysuiStatusBarStateController mStatusBarStateController;
@@ -695,7 +695,7 @@
             ShadeLogger shadeLogger,
             @ShadeDisplayAware ConfigurationController configurationController,
             Provider<FlingAnimationUtils.Builder> flingAnimationUtilsBuilder,
-            StatusBarTouchableRegionManager statusBarTouchableRegionManager,
+            ShadeTouchableRegionManager shadeTouchableRegionManager,
             ConversationNotificationManager conversationNotificationManager,
             MediaHierarchyManager mediaHierarchyManager,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
@@ -840,7 +840,7 @@
         mVibratorHelper = vibratorHelper;
         mMSDLPlayer = msdlPlayer;
         mVibrateOnOpening = mResources.getBoolean(R.bool.config_vibrateOnIconAnimation);
-        mStatusBarTouchableRegionManager = statusBarTouchableRegionManager;
+        mShadeTouchableRegionManager = shadeTouchableRegionManager;
         mSystemClock = systemClock;
         mKeyguardMediaController = keyguardMediaController;
         mMetricsLogger = metricsLogger;
@@ -1551,7 +1551,7 @@
 
     private Rect calculateGestureExclusionRect() {
         Rect exclusionRect = null;
-        Region touchableRegion = mStatusBarTouchableRegionManager.calculateTouchableRegion();
+        Region touchableRegion = mShadeTouchableRegionManager.calculateTouchableRegion();
         if (isFullyCollapsed() && touchableRegion != null) {
             // Note: The manager also calculates the non-pinned touchable region
             exclusionRect = touchableRegion.getBounds();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
index 04f89be..0df2299 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
@@ -98,7 +98,7 @@
 import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
+import com.android.systemui.statusbar.phone.ShadeTouchableRegionManager;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.SplitShadeStateController;
@@ -141,7 +141,7 @@
     private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
     private final NotificationShadeDepthController mDepthController;
     private final ShadeHeaderController mShadeHeaderController;
-    private final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
+    private final ShadeTouchableRegionManager mShadeTouchableRegionManager;
     private final Provider<StatusBarLongPressGestureDetector> mStatusBarLongPressGestureDetector;
     private final KeyguardStateController mKeyguardStateController;
     private final KeyguardBypassController mKeyguardBypassController;
@@ -317,7 +317,7 @@
             LockscreenShadeTransitionController lockscreenShadeTransitionController,
             NotificationShadeDepthController notificationShadeDepthController,
             ShadeHeaderController shadeHeaderController,
-            StatusBarTouchableRegionManager statusBarTouchableRegionManager,
+            ShadeTouchableRegionManager shadeTouchableRegionManager,
             Provider<StatusBarLongPressGestureDetector> statusBarLongPressGestureDetector,
             KeyguardStateController keyguardStateController,
             KeyguardBypassController keyguardBypassController,
@@ -366,7 +366,7 @@
         mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
         mDepthController = notificationShadeDepthController;
         mShadeHeaderController = shadeHeaderController;
-        mStatusBarTouchableRegionManager = statusBarTouchableRegionManager;
+        mShadeTouchableRegionManager = shadeTouchableRegionManager;
         mStatusBarLongPressGestureDetector = statusBarLongPressGestureDetector;
         mKeyguardStateController = keyguardStateController;
         mKeyguardBypassController = keyguardBypassController;
@@ -695,7 +695,7 @@
                 /* right= */ (int) mQsFrame.getX() + mQsFrame.getWidth(),
                 /* bottom= */ headerBottom + frameTop);
         // Also allow QS to intercept if the touch is near the notch.
-        mStatusBarTouchableRegionManager.updateRegionForNotch(mInterceptRegion);
+        mShadeTouchableRegionManager.updateRegionForNotch(mInterceptRegion);
         final boolean onHeader = mInterceptRegion.contains((int) x, (int) y);
 
         if (getExpanded()) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAware.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAware.kt
index 111d335..e8cdf836 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAware.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAware.kt
@@ -29,5 +29,13 @@
  * `ConfigurationController`) will be dynamically updated to reflect the current display's
  * configuration. This ensures consistent rendering even when the shade window is moved to an
  * external display.
+ *
+ * Note that in SystemUI, Currently, the shade window includes the lockscreen, quick settings, the
+ * notification stack, AOD, Bouncer, Glancable hub, and potentially other components that have been
+ * introduced after this comment is written.
+ *
+ * TODO: b/378016985 - The usage of this annotation in the relevant packages will be enforced by a
+ *   presubmit linter that will highlight instances of the global instances used in shade window
+ *   classes.
  */
 @Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class ShadeDisplayAware
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
index 4f73a345..91ca2ca 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
@@ -19,7 +19,8 @@
 import android.content.Context
 import android.content.res.Resources
 import android.view.LayoutInflater
-import android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
+import android.view.WindowManager
+import android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE
 import com.android.systemui.CoreStartable
 import com.android.systemui.common.ui.ConfigurationState
 import com.android.systemui.common.ui.ConfigurationStateImpl
@@ -30,16 +31,22 @@
 import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractorImpl
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.res.R
+import com.android.systemui.scene.ui.view.WindowRootView
+import com.android.systemui.shade.data.repository.MutableShadeDisplaysRepository
 import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
 import com.android.systemui.shade.data.repository.ShadeDisplaysRepositoryImpl
+import com.android.systemui.shade.display.ShadeDisplayPolicyModule
+import com.android.systemui.shade.domain.interactor.ShadeDisplaysInteractor
 import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
 import com.android.systemui.statusbar.phone.ConfigurationForwarder
 import com.android.systemui.statusbar.policy.ConfigurationController
+import dagger.BindsOptionalOf
 import dagger.Module
 import dagger.Provides
 import dagger.multibindings.ClassKey
 import dagger.multibindings.IntoMap
+import javax.inject.Provider
 
 /**
  * Module responsible for managing display-specific components and resources for the notification
@@ -53,7 +60,7 @@
  * By using this dedicated module, we ensure the notification shade window always utilizes the
  * correct display context and resources, regardless of the display it's on.
  */
-@Module
+@Module(includes = [OptionalShadeDisplayAwareBindings::class, ShadeDisplayPolicyModule::class])
 object ShadeDisplayAwareModule {
 
     /** Creates a new context for the shade window. */
@@ -63,7 +70,7 @@
     fun provideShadeDisplayAwareContext(context: Context): Context {
         return if (ShadeWindowGoesAround.isEnabled) {
             context
-                .createWindowContext(context.display, TYPE_APPLICATION_OVERLAY, /* options= */ null)
+                .createWindowContext(context.display, TYPE_NOTIFICATION_SHADE, /* options= */ null)
                 .apply { setTheme(R.style.Theme_SystemUI) }
         } else {
             context
@@ -73,6 +80,20 @@
     @Provides
     @ShadeDisplayAware
     @SysUISingleton
+    fun provideShadeWindowManager(
+        defaultWindowManager: WindowManager,
+        @ShadeDisplayAware context: Context,
+    ): WindowManager {
+        return if (ShadeWindowGoesAround.isEnabled) {
+            context.getSystemService(WindowManager::class.java) as WindowManager
+        } else {
+            defaultWindowManager
+        }
+    }
+
+    @Provides
+    @ShadeDisplayAware
+    @SysUISingleton
     fun provideShadeDisplayAwareResources(@ShadeDisplayAware context: Context): Resources {
         return context.resources
     }
@@ -162,6 +183,15 @@
         return impl
     }
 
+    @SysUISingleton
+    @Provides
+    fun provideMutableShadePositionRepository(
+        impl: ShadeDisplaysRepositoryImpl
+    ): MutableShadeDisplaysRepository {
+        ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
+        return impl
+    }
+
     @Provides
     @IntoMap
     @ClassKey(ShadePrimaryDisplayCommand::class)
@@ -172,4 +202,20 @@
             CoreStartable.NOP
         }
     }
+
+    @Provides
+    @IntoMap
+    @ClassKey(ShadeDisplaysInteractor::class)
+    fun provideShadeDisplaysInteractor(impl: Provider<ShadeDisplaysInteractor>): CoreStartable {
+        return if (ShadeWindowGoesAround.isEnabled) {
+            impl.get()
+        } else {
+            CoreStartable.NOP
+        }
+    }
+}
+
+@Module
+internal interface OptionalShadeDisplayAwareBindings {
+    @BindsOptionalOf fun bindOptionalOfWindowRootView(): WindowRootView
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt
index a5d9e96..a54f6b9 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt
@@ -20,11 +20,14 @@
 import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.display.data.repository.DisplayRepository
-import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
+import com.android.systemui.shade.data.repository.MutableShadeDisplaysRepository
+import com.android.systemui.shade.display.ShadeDisplayPolicy
+import com.android.systemui.shade.display.SpecificDisplayIdPolicy
 import com.android.systemui.statusbar.commandline.Command
 import com.android.systemui.statusbar.commandline.CommandRegistry
 import java.io.PrintWriter
 import javax.inject.Inject
+import kotlin.text.toIntOrNull
 
 @SysUISingleton
 class ShadePrimaryDisplayCommand
@@ -32,7 +35,9 @@
 constructor(
     private val commandRegistry: CommandRegistry,
     private val displaysRepository: DisplayRepository,
-    private val positionRepository: ShadeDisplaysRepository,
+    private val positionRepository: MutableShadeDisplaysRepository,
+    private val policies: Set<@JvmSuppressWildcards ShadeDisplayPolicy>,
+    private val defaultPolicy: ShadeDisplayPolicy,
 ) : Command, CoreStartable {
 
     override fun start() {
@@ -40,8 +45,11 @@
     }
 
     override fun help(pw: PrintWriter) {
-        pw.println("shade_display_override <displayId> ")
-        pw.println("Set the display which is holding the shade.")
+        pw.println("shade_display_override (<displayId>|<policyName>) ")
+        pw.println("Set the display which is holding the shade, or the policy that defines it.")
+        pw.println()
+        pw.println("shade_display_override policies")
+        pw.println("Lists available policies")
         pw.println()
         pw.println("shade_display_override reset ")
         pw.println("Reset the display which is holding the shade.")
@@ -68,21 +76,27 @@
                 "reset" -> reset()
                 "list",
                 "status" -> printStatus()
+                "policies" -> printPolicies()
                 "any_external" -> anyExternal()
-                else -> {
-                    val cmdAsInteger = command?.toIntOrNull()
-                    if (cmdAsInteger != null) {
-                        changeDisplay(displayId = cmdAsInteger)
-                    } else {
-                        help(pw)
-                    }
+                null -> help(pw)
+                else -> parsePolicy(command)
+            }
+        }
+
+        private fun parsePolicy(policyIdentifier: String) {
+            val displayId = policyIdentifier.toIntOrNull()
+            when {
+                displayId != null -> changeDisplay(displayId = displayId)
+                policies.any { it.name == policyIdentifier } -> {
+                    positionRepository.policy.value = policies.first { it.name == policyIdentifier }
                 }
+                else -> help(pw)
             }
         }
 
         private fun reset() {
-            positionRepository.resetDisplayId()
-            pw.println("Reset shade primary display id to ${Display.DEFAULT_DISPLAY}")
+            positionRepository.policy.value = defaultPolicy
+            pw.println("Reset shade display policy to default policy: ${defaultPolicy.name}")
         }
 
         private fun printStatus() {
@@ -95,6 +109,15 @@
             }
         }
 
+        private fun printPolicies() {
+            val currentPolicyName = positionRepository.policy.value.name
+            pw.println("Available policies: ")
+            policies.forEach {
+                pw.print(" - ${it.name}")
+                pw.println(if (currentPolicyName == it.name) " (Current policy)" else "")
+            }
+        }
+
         private fun anyExternal() {
             val anyExternalDisplay =
                 displaysRepository.displays.value.firstOrNull {
@@ -116,7 +139,7 @@
         }
 
         private fun setDisplay(id: Int) {
-            positionRepository.setDisplayId(id)
+            positionRepository.policy.value = SpecificDisplayIdPolicy(id)
             pw.println("New shade primary display id is $id")
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
index 7346a28..9ca23f0 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
@@ -19,8 +19,8 @@
 import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractor
 import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor
 import com.android.systemui.statusbar.GestureRecorder
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.phone.CentralSurfaces
-import com.android.systemui.statusbar.policy.HeadsUpManager
 
 /**
  * Allows CentralSurfacesImpl to interact with the shade. Only CentralSurfacesImpl should reference
@@ -37,7 +37,7 @@
         centralSurfaces: CentralSurfaces,
         recorder: GestureRecorder,
         hideExpandedRunnable: Runnable,
-        headsUpManager: HeadsUpManager
+        headsUpManager: HeadsUpManager,
     )
 
     /** Cancels any pending collapses. */
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurfaceImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurfaceImpl.kt
index ec4018c..3bbda16 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurfaceImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurfaceImpl.kt
@@ -17,8 +17,8 @@
 package com.android.systemui.shade
 
 import com.android.systemui.statusbar.GestureRecorder
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.phone.CentralSurfaces
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import javax.inject.Inject
 
 class ShadeSurfaceImpl @Inject constructor() : ShadeSurface, ShadeViewControllerEmptyImpl() {
@@ -26,7 +26,7 @@
         centralSurfaces: CentralSurfaces,
         recorder: GestureRecorder,
         hideExpandedRunnable: Runnable,
-        headsUpManager: HeadsUpManager
+        headsUpManager: HeadsUpManager,
     ) {}
 
     override fun cancelPendingCollapse() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt
index 71c5658..732d4d1 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt
@@ -23,14 +23,14 @@
 class FakeShadeDisplayRepository : ShadeDisplaysRepository {
     private val _displayId = MutableStateFlow(Display.DEFAULT_DISPLAY)
 
-    override fun setDisplayId(displayId: Int) {
+    fun setDisplayId(displayId: Int) {
         _displayId.value = displayId
     }
 
     override val displayId: StateFlow<Int>
         get() = _displayId
 
-    override fun resetDisplayId() {
+    fun resetDisplayId() {
         _displayId.value = Display.DEFAULT_DISPLAY
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt
index 4a95e33..756241e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt
@@ -18,37 +18,40 @@
 
 import android.view.Display
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.shade.display.ShadeDisplayPolicy
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.stateIn
 
+/** Source of truth for the display currently holding the shade. */
 interface ShadeDisplaysRepository {
     /** ID of the display which currently hosts the shade */
     val displayId: StateFlow<Int>
-
-    /**
-     * Updates the value of the shade display id stored, emitting to the new display id to every
-     * component dependent on the shade display id
-     */
-    fun setDisplayId(displayId: Int)
-
-    /** Resets value of shade primary display to the default display */
-    fun resetDisplayId()
 }
 
-/** Source of truth for the display currently holding the shade. */
+/** Allows to change the policy that determines in which display the Shade window is visible. */
+interface MutableShadeDisplaysRepository : ShadeDisplaysRepository {
+    /** Updates the policy to select where the shade is visible. */
+    val policy: MutableStateFlow<ShadeDisplayPolicy>
+}
+
+/** Keeps the policy and propagates the display id for the shade from it. */
 @SysUISingleton
-class ShadeDisplaysRepositoryImpl @Inject constructor() : ShadeDisplaysRepository {
-    private val _displayId = MutableStateFlow(Display.DEFAULT_DISPLAY)
+@OptIn(ExperimentalCoroutinesApi::class)
+class ShadeDisplaysRepositoryImpl
+@Inject
+constructor(defaultPolicy: ShadeDisplayPolicy, @Background bgScope: CoroutineScope) :
+    MutableShadeDisplaysRepository {
+    override val policy = MutableStateFlow<ShadeDisplayPolicy>(defaultPolicy)
 
-    override val displayId: StateFlow<Int>
-        get() = _displayId
-
-    override fun setDisplayId(displayId: Int) {
-        _displayId.value = displayId
-    }
-
-    override fun resetDisplayId() {
-        _displayId.value = Display.DEFAULT_DISPLAY
-    }
+    override val displayId: StateFlow<Int> =
+        policy
+            .flatMapLatest { it.displayId }
+            .stateIn(bgScope, SharingStarted.WhileSubscribed(), Display.DEFAULT_DISPLAY)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/display/AnyExternalShadeDisplayPolicy.kt b/packages/SystemUI/src/com/android/systemui/shade/display/AnyExternalShadeDisplayPolicy.kt
new file mode 100644
index 0000000..3f6c949
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/display/AnyExternalShadeDisplayPolicy.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.shade.display
+
+import android.view.Display
+import android.view.Display.DEFAULT_DISPLAY
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.display.data.repository.DisplayRepository
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * Returns an external display if one exists, otherwise the default display.
+ *
+ * If there are multiple external displays, the one with minimum display ID is returned.
+ */
+@SysUISingleton
+class AnyExternalShadeDisplayPolicy
+@Inject
+constructor(displayRepository: DisplayRepository, @Background bgScope: CoroutineScope) :
+    ShadeDisplayPolicy {
+    override val name: String
+        get() = "any_external_display"
+
+    override val displayId: StateFlow<Int> =
+        displayRepository.displays
+            .map { displays ->
+                displays
+                    .filter { it.displayId != DEFAULT_DISPLAY && it.type in ALLOWED_DISPLAY_TYPES }
+                    .minOfOrNull { it.displayId } ?: DEFAULT_DISPLAY
+            }
+            .stateIn(bgScope, SharingStarted.WhileSubscribed(), DEFAULT_DISPLAY)
+
+    private companion object {
+        val ALLOWED_DISPLAY_TYPES =
+            setOf(Display.TYPE_EXTERNAL, Display.TYPE_OVERLAY, Display.TYPE_WIFI)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt b/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt
new file mode 100644
index 0000000..1b22ee4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.shade.display
+
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.IntoSet
+import kotlinx.coroutines.flow.StateFlow
+
+/** Describes the display the shade should be shown in. */
+interface ShadeDisplayPolicy {
+    val name: String
+
+    /** The display id the shade should be at, according to this policy. */
+    val displayId: StateFlow<Int>
+}
+
+@Module
+interface ShadeDisplayPolicyModule {
+    @IntoSet
+    @Binds
+    fun provideDefaultPolicyToSet(impl: DefaultShadeDisplayPolicy): ShadeDisplayPolicy
+
+    @IntoSet
+    @Binds
+    fun provideAnyExternalShadeDisplayPolicyToSet(
+        impl: AnyExternalShadeDisplayPolicy
+    ): ShadeDisplayPolicy
+
+    @Binds fun provideDefaultPolicy(impl: DefaultShadeDisplayPolicy): ShadeDisplayPolicy
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/display/SpecificDisplayIdPolicy.kt b/packages/SystemUI/src/com/android/systemui/shade/display/SpecificDisplayIdPolicy.kt
new file mode 100644
index 0000000..13e7664
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/display/SpecificDisplayIdPolicy.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.shade.display
+
+import android.view.Display
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+/** Policy to specify a display id explicitly. */
+open class SpecificDisplayIdPolicy(displayId: Int) : ShadeDisplayPolicy {
+    override val name: String
+        get() = "display_${displayId}_policy"
+
+    override val displayId: StateFlow<Int> = MutableStateFlow(displayId)
+}
+
+class DefaultShadeDisplayPolicy @Inject constructor() :
+    SpecificDisplayIdPolicy(Display.DEFAULT_DISPLAY)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
index 1055dcb..fb2cbec 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
@@ -18,21 +18,21 @@
 
 import android.content.Context
 import android.util.Log
-import android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE
+import android.view.WindowManager
+import androidx.annotation.UiThread
 import com.android.app.tracing.coroutines.launchTraced
 import com.android.app.tracing.traceSection
 import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
-import com.android.systemui.display.shared.model.DisplayWindowProperties
 import com.android.systemui.scene.ui.view.WindowRootView
 import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.shade.ShadeWindowLayoutParams
 import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
 import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
-import com.android.systemui.statusbar.phone.ConfigurationForwarder
+import com.android.systemui.util.kotlin.getOrNull
+import java.util.Optional
 import javax.inject.Inject
 import kotlin.coroutines.CoroutineContext
 import kotlinx.coroutines.CoroutineScope
@@ -43,15 +43,27 @@
 class ShadeDisplaysInteractor
 @Inject
 constructor(
-    private val shadeRootView: WindowRootView,
+    optionalShadeRootView: Optional<WindowRootView>,
     private val shadePositionRepository: ShadeDisplaysRepository,
     @ShadeDisplayAware private val shadeContext: Context,
-    private val displayWindowPropertiesRepository: DisplayWindowPropertiesRepository,
+    @ShadeDisplayAware private val wm: WindowManager,
     @Background private val bgScope: CoroutineScope,
-    @ShadeDisplayAware private val configurationForwarder: ConfigurationForwarder,
-    @Main private val mainContext: CoroutineContext,
+    @Main private val mainThreadContext: CoroutineContext,
 ) : CoreStartable {
 
+    private val shadeLayoutParams: WindowManager.LayoutParams =
+        ShadeWindowLayoutParams.create(shadeContext)
+
+    private val shadeRootView =
+        optionalShadeRootView.getOrNull()
+            ?: error(
+                """
+            ShadeRootView must be provided for this ShadeDisplayInteractor to work.
+            If it is not, it means this is being instantiated in a SystemUI variant that shouldn't.
+            """
+                    .trimIndent()
+            )
+
     override fun start() {
         ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
         bgScope.launchTraced(TAG) {
@@ -60,51 +72,52 @@
     }
 
     /** Tries to move the shade. If anything wrong happens, fails gracefully without crashing. */
-    private suspend fun moveShadeWindowTo(destinationDisplayId: Int) {
-        val currentId = shadeRootView.display.displayId
-        if (currentId == destinationDisplayId) {
+    private suspend fun moveShadeWindowTo(destinationId: Int) {
+        Log.d(TAG, "Trying to move shade window to display with id $destinationId")
+        val currentDisplay = shadeRootView.display
+        if (currentDisplay == null) {
+            Log.w(TAG, "Current shade display is null")
+            return
+        }
+        val currentId = currentDisplay.displayId
+        if (currentId == destinationId) {
             Log.w(TAG, "Trying to move the shade to a display it was already in")
             return
         }
         try {
-            moveShadeWindow(fromId = currentId, toId = destinationDisplayId)
+            withContext(mainThreadContext) { moveShadeWindow(toId = destinationId) }
         } catch (e: IllegalStateException) {
             Log.e(
                 TAG,
-                "Unable to move the shade window from display $currentId to $destinationDisplayId",
+                "Unable to move the shade window from display $currentId to $destinationId",
                 e,
             )
         }
     }
 
-    private suspend fun moveShadeWindow(fromId: Int, toId: Int) {
-        val sourceProperties = getDisplayWindowProperties(fromId)
-        val destinationProperties = getDisplayWindowProperties(toId)
-        traceSection({ "MovingShadeWindow from $fromId to $toId" }) {
-            withContext(mainContext) {
-                traceSection("removeView") {
-                    sourceProperties.windowManager.removeView(shadeRootView)
-                }
-                traceSection("addView") {
-                    destinationProperties.windowManager.addView(
-                        shadeRootView,
-                        ShadeWindowLayoutParams.create(shadeContext),
-                    )
-                }
-            }
-        }
-        traceSection("SecondaryShadeInteractor#onConfigurationChanged") {
-            configurationForwarder.onConfigurationChanged(
-                destinationProperties.context.resources.configuration
-            )
+    @UiThread
+    private fun moveShadeWindow(toId: Int) {
+        traceSection({ "moveShadeWindow  to $toId" }) {
+            removeShadeWindow()
+            updateContextDisplay(toId)
+            addShadeWindow()
         }
     }
 
-    private fun getDisplayWindowProperties(displayId: Int): DisplayWindowProperties {
-        return displayWindowPropertiesRepository.get(displayId, TYPE_NOTIFICATION_SHADE)
+    @UiThread
+    private fun removeShadeWindow(): Unit =
+        traceSection("removeShadeWindow") { wm.removeView(shadeRootView) }
+
+    @UiThread
+    private fun addShadeWindow(): Unit =
+        traceSection("addShadeWindow") { wm.addView(shadeRootView, shadeLayoutParams) }
+
+    @UiThread
+    private fun updateContextDisplay(newDisplayId: Int) {
+        traceSection("updateContextDisplay") { shadeContext.updateDisplay(newDisplayId) }
     }
 
     private companion object {
-        const val TAG = "SecondaryShadeInteractor"
+        const val TAG = "ShadeDisplaysInteractor"
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
index 45516aa..0d847d8 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
@@ -23,6 +23,7 @@
 import android.icu.text.DisplayContext
 import android.os.UserHandle
 import android.provider.Settings
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.lifecycle.ExclusiveActivatable
 import com.android.systemui.plugins.ActivityStarter
@@ -48,7 +49,6 @@
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 /** Models UI state for the shade header. */
 class ShadeHeaderViewModel
@@ -87,10 +87,6 @@
     /** Whether or not the privacy chip is enabled in the device privacy config. */
     val isPrivacyChipEnabled: StateFlow<Boolean> = privacyChipInteractor.isChipEnabled
 
-    private val _isDisabled = MutableStateFlow(false)
-    /** Whether or not the Shade Header should be disabled based on disableFlags. */
-    val isDisabled: StateFlow<Boolean> = _isDisabled.asStateFlow()
-
     private val longerPattern = context.getString(R.string.abbrev_wday_month_day_no_year_alarm)
     private val shorterPattern = context.getString(R.string.abbrev_month_day_no_year)
     private val longerDateFormat = MutableStateFlow(getFormatFromPattern(longerPattern))
@@ -132,8 +128,6 @@
                     .collect { _mobileSubIds.value = it }
             }
 
-            launch { shadeInteractor.isQsEnabled.map { !it }.collect { _isDisabled.value = it } }
-
             awaitCancellation()
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModel.kt
index ce4c081..02531221 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModel.kt
@@ -30,15 +30,21 @@
 import com.android.systemui.settings.brightness.ui.viewModel.BrightnessMirrorViewModel
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.shade.shared.model.ShadeMode
+import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor
 import com.android.systemui.unfold.domain.interactor.UnfoldTransitionInteractor
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import java.util.concurrent.atomic.AtomicBoolean
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
 
 /**
  * Models UI state used to render the content of the shade scene.
@@ -54,6 +60,7 @@
     val brightnessMirrorViewModelFactory: BrightnessMirrorViewModel.Factory,
     val mediaCarouselInteractor: MediaCarouselInteractor,
     shadeInteractor: ShadeInteractor,
+    private val disableFlagsInteractor: DisableFlagsInteractor,
     private val footerActionsViewModelFactory: FooterActionsViewModel.Factory,
     private val footerActionsController: FooterActionsController,
     private val unfoldTransitionInteractor: UnfoldTransitionInteractor,
@@ -70,12 +77,21 @@
 
     val isMediaVisible: StateFlow<Boolean> = mediaCarouselInteractor.hasActiveMediaOrRecommendation
 
+    private val _isQsEnabled =
+        MutableStateFlow(!disableFlagsInteractor.disableFlags.value.isQuickSettingsEnabled())
+    val isQsEnabled: StateFlow<Boolean> = _isQsEnabled.asStateFlow()
+
     private val footerActionsControllerInitialized = AtomicBoolean(false)
 
-    override suspend fun onActivated(): Nothing {
-        deviceEntryInteractor.isDeviceEntered.collect { isDeviceEntered ->
-            _isEmptySpaceClickable.value = !isDeviceEntered
-        }
+    override suspend fun onActivated(): Nothing = coroutineScope {
+        deviceEntryInteractor.isDeviceEntered
+            .onEach { isDeviceEntered -> _isEmptySpaceClickable.value = !isDeviceEntered }
+            .launchIn(this)
+        disableFlagsInteractor.disableFlags
+            .map { it.isQuickSettingsEnabled() }
+            .onEach { _isQsEnabled.value = it }
+            .launchIn(this)
+        awaitCancellation()
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActions.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActions.kt
index b0777c9..dd1b58c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActions.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActions.kt
@@ -27,24 +27,28 @@
 
 /** Returns collection of [UserAction] to [UserActionResult] pairs for opening the single shade. */
 fun singleShadeActions(
-    requireTwoPointersForTopEdgeForQs: Boolean = false
+    isDownFromTopEdgeEnabled: Boolean = true,
+    requireTwoPointersForTopEdgeForQs: Boolean = false,
 ): Array<Pair<UserAction, UserActionResult>> {
     val shadeUserActionResult = UserActionResult(Scenes.Shade, isIrreversible = true)
     val qsSceneUserActionResult = UserActionResult(Scenes.QuickSettings, isIrreversible = true)
-    return arrayOf(
-        // Swiping down, not from the edge, always goes to shade.
-        Swipe.Down to shadeUserActionResult,
-        Swipe.Down(pointerCount = 2) to shadeUserActionResult,
-
-        // Swiping down from the top edge.
-        swipeDownFromTop(pointerCount = 1) to
-            if (requireTwoPointersForTopEdgeForQs) {
-                shadeUserActionResult
-            } else {
-                qsSceneUserActionResult
-            },
-        swipeDownFromTop(pointerCount = 2) to qsSceneUserActionResult,
-    )
+    return buildList {
+            // Swiping down, not from the edge, always goes to shade.
+            add(Swipe.Down to shadeUserActionResult)
+            add(Swipe.Down(pointerCount = 2) to shadeUserActionResult)
+            if (isDownFromTopEdgeEnabled) {
+                add(
+                    swipeDownFromTop(pointerCount = 1) to
+                        if (requireTwoPointersForTopEdgeForQs) {
+                            shadeUserActionResult
+                        } else {
+                            qsSceneUserActionResult
+                        }
+                )
+                add(swipeDownFromTop(pointerCount = 2) to qsSceneUserActionResult)
+            }
+        }
+        .toTypedArray()
 }
 
 /** Returns collection of [UserAction] to [UserActionResult] pairs for opening the split shade. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS
index c019f30..72b03bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS
@@ -14,7 +14,7 @@
 per-file *Keyboard* = file:../keyguard/OWNERS
 per-file *Keyguard* = set noparent
 per-file *Keyguard* = file:../keyguard/OWNERS
-per-file *Notification* = set noparent
+# Not setting noparent here, since *Notification* also matches some status bar notification chips files (statusbar/chips/notification) which should be owned by the status bar team.
 per-file *Notification* = file:notification/OWNERS
 # Not setting noparent here, since *Mode* matches many other classes (e.g., *ViewModel*)
 per-file *Mode* = file:notification/OWNERS
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index e19fcd0..85b8bf9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -39,24 +39,24 @@
 import com.android.systemui.res.R
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import java.io.PrintWriter
 import javax.inject.Inject
 import kotlin.math.max
 
 /**
  * A utility class that handles notification panel expansion when a user swipes downward on a
- * notification from the pulsing state.
- * If face-bypass is enabled, the user can swipe down anywhere on the screen (not just from a
- * notification) to trigger the notification panel expansion.
+ * notification from the pulsing state. If face-bypass is enabled, the user can swipe down anywhere
+ * on the screen (not just from a notification) to trigger the notification panel expansion.
  */
 @SysUISingleton
-class PulseExpansionHandler @Inject
+class PulseExpansionHandler
+@Inject
 constructor(
     context: Context,
     private val wakeUpCoordinator: NotificationWakeUpCoordinator,
@@ -67,7 +67,7 @@
     private val falsingManager: FalsingManager,
     private val shadeInteractor: ShadeInteractor,
     private val lockscreenShadeTransitionController: LockscreenShadeTransitionController,
-    dumpManager: DumpManager
+    dumpManager: DumpManager,
 ) : Gefingerpoken, Dumpable {
     companion object {
         private val SPRING_BACK_ANIMATION_LENGTH_MS = 375
@@ -91,14 +91,13 @@
                         pulseExpandAbortListener?.run()
                     }
                 }
-                headsUpManager.unpinAll(
-                    /*userUnPinned= */
-                    true,
-                )
+                headsUpManager.unpinAll(/* userUnPinned= */ true)
             }
         }
+
     var leavingLockscreen: Boolean = false
         private set
+
     private var touchSlop = 0f
     private var minDragDistance = 0
     private lateinit var stackScrollerController: NotificationStackScrollLayoutController
@@ -111,24 +110,27 @@
 
     private val isFalseTouch: Boolean
         get() = falsingManager.isFalseTouch(NOTIFICATION_DRAG_DOWN)
+
     var pulseExpandAbortListener: Runnable? = null
     var bouncerShowing: Boolean = false
 
     init {
         initResources(context)
-        configurationController.addCallback(object : ConfigurationController.ConfigurationListener {
-            override fun onConfigChanged(newConfig: Configuration?) {
-                initResources(context)
+        configurationController.addCallback(
+            object : ConfigurationController.ConfigurationListener {
+                override fun onConfigChanged(newConfig: Configuration?) {
+                    initResources(context)
+                }
             }
-        })
+        )
 
         mPowerManager = context.getSystemService(PowerManager::class.java)
         dumpManager.registerDumpable(this)
     }
 
     private fun initResources(context: Context) {
-        minDragDistance = context.resources.getDimensionPixelSize(
-            R.dimen.keyguard_drag_down_min_distance)
+        minDragDistance =
+            context.resources.getDimensionPixelSize(R.dimen.keyguard_drag_down_min_distance)
         touchSlop = ViewConfiguration.get(context).scaledTouchSlop.toFloat()
     }
 
@@ -137,7 +139,8 @@
     }
 
     private fun canHandleMotionEvent(): Boolean {
-        return wakeUpCoordinator.canShowPulsingHuns && !shadeInteractor.isQsExpanded.value &&
+        return wakeUpCoordinator.canShowPulsingHuns &&
+            !shadeInteractor.isQsExpanded.value &&
             !bouncerShowing
     }
 
@@ -189,18 +192,20 @@
     }
 
     override fun onTouchEvent(event: MotionEvent): Boolean {
-        val finishExpanding = (event.action == MotionEvent.ACTION_CANCEL ||
-            event.action == MotionEvent.ACTION_UP) && isExpanding
+        val finishExpanding =
+            (event.action == MotionEvent.ACTION_CANCEL || event.action == MotionEvent.ACTION_UP) &&
+                isExpanding
 
-        val isDraggingNotificationOrCanBypass = mStartingChild?.showingPulsing() == true ||
-            bypassController.canBypass()
+        val isDraggingNotificationOrCanBypass =
+            mStartingChild?.showingPulsing() == true || bypassController.canBypass()
         if ((!canHandleMotionEvent() || !isDraggingNotificationOrCanBypass) && !finishExpanding) {
             // We allow cancellations/finishing to still go through here to clean up the state
             return false
         }
 
-        if (velocityTracker == null || !isExpanding ||
-            event.actionMasked == MotionEvent.ACTION_DOWN) {
+        if (
+            velocityTracker == null || !isExpanding || event.actionMasked == MotionEvent.ACTION_DOWN
+        ) {
             return startExpansion(event)
         }
         velocityTracker!!.addMovement(event)
@@ -210,12 +215,11 @@
         when (event.actionMasked) {
             MotionEvent.ACTION_MOVE -> updateExpansionHeight(moveDistance)
             MotionEvent.ACTION_UP -> {
-                velocityTracker!!.computeCurrentVelocity(
-                    /* units= */
-                    1000,
-                )
-                val canExpand = moveDistance > 0 && velocityTracker!!.getYVelocity() > -1000 &&
-                    statusBarStateController.state != StatusBarState.SHADE
+                velocityTracker!!.computeCurrentVelocity(/* units= */ 1000)
+                val canExpand =
+                    moveDistance > 0 &&
+                        velocityTracker!!.getYVelocity() > -1000 &&
+                        statusBarStateController.state != StatusBarState.SHADE
                 if (!falsingManager.isUnlockingDisabled && !isFalseTouch && canExpand) {
                     finishExpansion()
                 } else {
@@ -243,22 +247,16 @@
             mPowerManager!!.wakeUp(
                 SystemClock.uptimeMillis(),
                 PowerManager.WAKE_REASON_GESTURE,
-                "com.android.systemui:PULSEDRAG"
+                "com.android.systemui:PULSEDRAG",
             )
         }
-        lockscreenShadeTransitionController.goToLockedShade(
-            startingChild,
-            needsQSAnimation = false
-        )
+        lockscreenShadeTransitionController.goToLockedShade(startingChild, needsQSAnimation = false)
         lockscreenShadeTransitionController.finishPulseAnimation(cancelled = false)
         leavingLockscreen = true
         isExpanding = false
         if (mStartingChild is ExpandableNotificationRow) {
             val row = mStartingChild as ExpandableNotificationRow?
-            row!!.onExpandedByGesture(
-                /*userExpanded= */
-                true,
-            )
+            row!!.onExpandedByGesture(/* userExpanded= */ true)
         }
     }
 
@@ -266,19 +264,15 @@
         var expansionHeight = max(height, 0.0f)
         if (mStartingChild != null) {
             val child = mStartingChild!!
-            val newHeight = Math.min(
-                (child.collapsedHeight + expansionHeight).toInt(),
-                child.maxContentHeight
-            )
+            val newHeight =
+                Math.min((child.collapsedHeight + expansionHeight).toInt(), child.maxContentHeight)
             child.actualHeight = newHeight
         } else {
             wakeUpCoordinator.setNotificationsVisibleForExpansion(
-                height
-                    > lockscreenShadeTransitionController.distanceUntilShowingPulsingNotifications,
-                /*animate= */
-                true,
-                /*increaseSpeed= */
-                true
+                height >
+                    lockscreenShadeTransitionController.distanceUntilShowingPulsingNotifications,
+                /*animate= */ true,
+                /*increaseSpeed= */ true,
             )
         }
         lockscreenShadeTransitionController.setPulseHeight(expansionHeight, animate = false)
@@ -296,7 +290,7 @@
     @VisibleForTesting
     fun reset(
         child: ExpandableView,
-        animationDuration: Long = SPRING_BACK_ANIMATION_LENGTH_MS.toLong()
+        animationDuration: Long = SPRING_BACK_ANIMATION_LENGTH_MS.toLong(),
     ) {
         if (child.actualHeight == child.collapsedHeight) {
             setUserLocked(child, false)
@@ -309,11 +303,13 @@
             // don't use reflection, because the `actualHeight` field may be obfuscated
             child.actualHeight = animation.animatedValue as Int
         }
-        anim.addListener(object : AnimatorListenerAdapter() {
-            override fun onAnimationEnd(animation: Animator) {
-                setUserLocked(child, false)
+        anim.addListener(
+            object : AnimatorListenerAdapter() {
+                override fun onAnimationEnd(animation: Animator) {
+                    setUserLocked(child, false)
+                }
             }
-        })
+        )
         anim.start()
     }
 
@@ -331,12 +327,9 @@
         }
         lockscreenShadeTransitionController.finishPulseAnimation(cancelled = true)
         wakeUpCoordinator.setNotificationsVisibleForExpansion(
-            /*visible= */
-            false,
-            /*animate= */
-            true,
-            /*increaseSpeed= */
-            false
+            /*visible= */ false,
+            /*animate= */ true,
+            /*increaseSpeed= */ false,
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipsModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipsModule.kt
index 8ce0dbf..6db610b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipsModule.kt
@@ -21,7 +21,10 @@
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.LogBufferFactory
 import com.android.systemui.statusbar.chips.notification.demo.ui.viewmodel.DemoNotifChipViewModel
+import com.android.systemui.statusbar.chips.notification.domain.interactor.StatusBarNotificationChipsInteractor
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import dagger.Binds
+import dagger.Lazy
 import dagger.Module
 import dagger.Provides
 import dagger.multibindings.ClassKey
@@ -41,5 +44,19 @@
         fun provideChipsLogBuffer(factory: LogBufferFactory): LogBuffer {
             return factory.create("StatusBarChips", 200)
         }
+
+        @Provides
+        @SysUISingleton
+        @IntoMap
+        @ClassKey(StatusBarNotificationChipsInteractor::class)
+        fun statusBarNotificationChipsInteractorAsCoreStartable(
+            interactorLazy: Lazy<StatusBarNotificationChipsInteractor>
+        ): CoreStartable {
+            return if (StatusBarNotifChips.isEnabled) {
+                interactorLazy.get()
+            } else {
+                CoreStartable.NOP
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
index af238f6..49c4479 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.chips.mediaprojection.domain.interactor
 
 import android.content.pm.PackageManager
+import android.media.projection.StopReason
 import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.Flags
 import com.android.systemui.dagger.SysUISingleton
@@ -105,7 +106,7 @@
 
     /** Stops the currently active projection. */
     fun stopProjecting() {
-        scope.launch { mediaProjectionRepository.stopProjecting() }
+        scope.launch { mediaProjectionRepository.stopProjecting(StopReason.STOP_PRIVACY_CHIP) }
     }
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
new file mode 100644
index 0000000..087b510
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
@@ -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 com.android.systemui.statusbar.chips.notification.domain.interactor
+
+import com.android.systemui.activity.data.repository.ActivityManagerRepository
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.Logger
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
+import com.android.systemui.statusbar.chips.StatusBarChipsLog
+import com.android.systemui.statusbar.chips.notification.domain.model.NotificationChipModel
+import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.map
+
+/**
+ * Interactor representing a single notification's status bar chip.
+ *
+ * [startingModel.key] dictates which notification this interactor corresponds to - all updates sent
+ * to this interactor via [setNotification] should only be for the notification with the same key.
+ *
+ * [StatusBarNotificationChipsInteractor] will collect all the individual instances of this
+ * interactor and send all the necessary information to the UI layer.
+ */
+@OptIn(ExperimentalCoroutinesApi::class)
+class SingleNotificationChipInteractor
+@AssistedInject
+constructor(
+    @Assisted startingModel: ActiveNotificationModel,
+    private val activityManagerRepository: ActivityManagerRepository,
+    @StatusBarChipsLog private val logBuffer: LogBuffer,
+) {
+    private val key = startingModel.key
+    private val logger = Logger(logBuffer, "Notif".pad())
+    // [StatusBarChipLogTag] recommends a max tag length of 20, so [extraLogTag] should NOT be the
+    // top-level tag. It should instead be provided as the first string in each log message.
+    private val extraLogTag = "SingleChipInteractor[key=$key]"
+
+    private val _notificationModel = MutableStateFlow(startingModel)
+
+    /**
+     * Sets the new notification info corresponding to this interactor. The key on [model] *must*
+     * match the key on the original [startingModel], otherwise the update won't be processed.
+     */
+    fun setNotification(model: ActiveNotificationModel) {
+        if (model.key != this.key) {
+            logger.w({ "$str1: received model for different key $str2" }) {
+                str1 = extraLogTag
+                str2 = model.key
+            }
+            return
+        }
+        _notificationModel.value = model
+    }
+
+    private val uid: Flow<Int> = _notificationModel.map { it.uid }
+
+    /** True if the application managing the notification is visible to the user. */
+    private val isAppVisible: Flow<Boolean> =
+        uid.flatMapLatest { currentUid ->
+            activityManagerRepository.createIsAppVisibleFlow(currentUid, logger, extraLogTag)
+        }
+
+    /**
+     * Emits this notification's status bar chip, or null if this notification shouldn't show a
+     * status bar chip.
+     */
+    val notificationChip: Flow<NotificationChipModel?> =
+        combine(_notificationModel, isAppVisible) { notif, isAppVisible ->
+            if (isAppVisible) {
+                // If the app that posted this notification is visible, we want to hide the chip
+                // because information between the status bar chip and the app itself could be
+                // out-of-sync (like a timer that's slightly off)
+                null
+            } else {
+                notif.toNotificationChipModel()
+            }
+        }
+
+    private fun ActiveNotificationModel.toNotificationChipModel(): NotificationChipModel? {
+        val statusBarChipIconView = this.statusBarChipIconView
+        if (statusBarChipIconView == null) {
+            logger.w({ "$str1: Can't show chip because status bar chip icon view is null" }) {
+                str1 = extraLogTag
+            }
+            return null
+        }
+        return NotificationChipModel(key, statusBarChipIconView)
+    }
+
+    @AssistedFactory
+    fun interface Factory {
+        fun create(startingModel: ActiveNotificationModel): SingleNotificationChipInteractor
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt
index 9e09671..e8cb35b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt
@@ -17,16 +17,42 @@
 package com.android.systemui.statusbar.chips.notification.domain.interactor
 
 import android.annotation.SuppressLint
+import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.Logger
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
+import com.android.systemui.statusbar.chips.StatusBarChipsLog
+import com.android.systemui.statusbar.chips.notification.domain.model.NotificationChipModel
 import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
+import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
+import com.android.systemui.util.kotlin.pairwise
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharedFlow
 import kotlinx.coroutines.flow.asSharedFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
 
 /** An interactor for the notification chips shown in the status bar. */
 @SysUISingleton
-class StatusBarNotificationChipsInteractor @Inject constructor() {
+@OptIn(ExperimentalCoroutinesApi::class)
+class StatusBarNotificationChipsInteractor
+@Inject
+constructor(
+    @Background private val backgroundScope: CoroutineScope,
+    private val activeNotificationsInteractor: ActiveNotificationsInteractor,
+    private val singleNotificationChipInteractorFactory: SingleNotificationChipInteractor.Factory,
+    @StatusBarChipsLog private val logBuffer: LogBuffer,
+) : CoreStartable {
+    private val logger = Logger(logBuffer, "AllNotifs".pad())
 
     // Each chip tap is an individual event, *not* a state, which is why we're using SharedFlow not
     // StateFlow. There shouldn't be multiple updates per frame, which should avoid performance
@@ -45,4 +71,79 @@
         StatusBarNotifChips.assertInNewMode()
         _promotedNotificationChipTapEvent.emit(key)
     }
+
+    /**
+     * A cache of interactors. Each currently-promoted notification should have a corresponding
+     * interactor in this map.
+     */
+    private val promotedNotificationInteractorMap =
+        mutableMapOf<String, SingleNotificationChipInteractor>()
+
+    /**
+     * A list of interactors. Each currently-promoted notification should have a corresponding
+     * interactor in this list.
+     */
+    private val promotedNotificationInteractors =
+        MutableStateFlow<List<SingleNotificationChipInteractor>>(emptyList())
+
+    override fun start() {
+        if (!StatusBarNotifChips.isEnabled) {
+            return
+        }
+
+        backgroundScope.launch("StatusBarNotificationChipsInteractor") {
+            activeNotificationsInteractor.promotedOngoingNotifications
+                .pairwise(initialValue = emptyList())
+                .collect { (oldNotifs, currentNotifs) ->
+                    val removedNotifs = oldNotifs.minus(currentNotifs.toSet())
+                    removedNotifs.forEach { removedNotif ->
+                        val wasRemoved = promotedNotificationInteractorMap.remove(removedNotif.key)
+                        if (wasRemoved == null) {
+                            logger.w({
+                                "Attempted to remove $str1 from interactor map but it wasn't present"
+                            }) {
+                                str1 = removedNotif.key
+                            }
+                        }
+                    }
+                    currentNotifs.forEach { notif ->
+                        val interactor =
+                            promotedNotificationInteractorMap.computeIfAbsent(notif.key) {
+                                singleNotificationChipInteractorFactory.create(notif)
+                            }
+                        interactor.setNotification(notif)
+                    }
+                    logger.d({ "Interactors: $str1" }) {
+                        str1 =
+                            promotedNotificationInteractorMap.keys.joinToString(separator = " /// ")
+                    }
+                    promotedNotificationInteractors.value =
+                        promotedNotificationInteractorMap.values.toList()
+                }
+        }
+    }
+
+    /**
+     * A flow modeling the notifications that should be shown as chips in the status bar. Emits an
+     * empty list if there are no notifications that should show a status bar chip.
+     */
+    val notificationChips: Flow<List<NotificationChipModel>> =
+        if (StatusBarNotifChips.isEnabled) {
+            // For all our current interactors...
+            promotedNotificationInteractors.flatMapLatest { interactors ->
+                if (interactors.isNotEmpty()) {
+                    // Combine each interactor's [notificationChip] flow...
+                    val allNotificationChips: List<Flow<NotificationChipModel?>> =
+                        interactors.map { interactor -> interactor.notificationChip }
+                    combine(allNotificationChips) {
+                        // ... and emit just the non-null chips
+                        it.filterNotNull()
+                    }
+                } else {
+                    flowOf(emptyList())
+                }
+            }
+        } else {
+            flowOf(emptyList())
+        }
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt
similarity index 66%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt
index 7d3d8b9..5698ee6 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
-}
+package com.android.systemui.statusbar.chips.notification.domain.model
+
+import com.android.systemui.statusbar.StatusBarIconView
+
+/** Modeling all the data needed to render a status bar notification chip. */
+data class NotificationChipModel(val key: String, val statusBarChipIconView: StatusBarIconView)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
index 7526748..9eff627 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
@@ -20,11 +20,10 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.statusbar.chips.notification.domain.interactor.StatusBarNotificationChipsInteractor
+import com.android.systemui.statusbar.chips.notification.domain.model.NotificationChipModel
 import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.chips.ui.model.ColorsModel
 import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
-import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
-import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
@@ -37,7 +36,6 @@
 @Inject
 constructor(
     @Application private val applicationScope: CoroutineScope,
-    activeNotificationsInteractor: ActiveNotificationsInteractor,
     private val notifChipsInteractor: StatusBarNotificationChipsInteractor,
 ) {
     /**
@@ -45,19 +43,14 @@
      * no notifications that should show a status bar chip.
      */
     val chips: Flow<List<OngoingActivityChipModel.Shown>> =
-        activeNotificationsInteractor.promotedOngoingNotifications.map { notifications ->
-            notifications.mapNotNull { it.toChipModel() }
+        notifChipsInteractor.notificationChips.map { notifications ->
+            notifications.map { it.toActivityChipModel() }
         }
 
-    /**
-     * Converts the notification to the [OngoingActivityChipModel] object. Returns null if the
-     * notification has invalid data such that it can't be displayed as a chip.
-     */
-    private fun ActiveNotificationModel.toChipModel(): OngoingActivityChipModel.Shown? {
+    /** Converts the notification to the [OngoingActivityChipModel] object. */
+    private fun NotificationChipModel.toActivityChipModel(): OngoingActivityChipModel.Shown {
         StatusBarNotifChips.assertInNewMode()
-        // TODO(b/364653005): Log error if there's no icon view.
-        val rawIcon = this.statusBarChipIconView ?: return null
-        val icon = OngoingActivityChipModel.ChipIcon.StatusBarView(rawIcon)
+        val icon = OngoingActivityChipModel.ChipIcon.StatusBarView(this.statusBarChipIconView)
         // TODO(b/364653005): Use the notification color if applicable.
         val colors = ColorsModel.Themed
         val onClickListener =
@@ -65,7 +58,9 @@
                 // The notification pipeline needs everything to run on the main thread, so keep
                 // this event on the main thread.
                 applicationScope.launch {
-                    notifChipsInteractor.onPromotedNotificationChipTapped(this@toChipModel.key)
+                    notifChipsInteractor.onPromotedNotificationChipTapped(
+                        this@toActivityChipModel.key
+                    )
                 }
             }
         return OngoingActivityChipModel.Shown.IconOnly(icon, colors, onClickListener)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarter.kt
index 84c7ab2..9e9a38e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarter.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.statusbar.data.repository.LightBarControllerStore
 import com.android.systemui.statusbar.data.repository.PrivacyDotWindowControllerStore
 import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore
+import com.android.systemui.statusbar.phone.AutoHideControllerStore
 import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.android.systemui.statusbar.window.data.repository.StatusBarWindowStateRepositoryStore
 import com.android.systemui.util.kotlin.pairwiseBy
@@ -50,6 +51,7 @@
     private val initializerStore: StatusBarInitializerStore,
     private val statusBarWindowControllerStore: StatusBarWindowControllerStore,
     private val statusBarInitializerStore: StatusBarInitializerStore,
+    private val autoHideControllerStore: AutoHideControllerStore,
     private val privacyDotWindowControllerStore: PrivacyDotWindowControllerStore,
     private val lightBarControllerStore: LightBarControllerStore,
 ) : CoreStartable {
@@ -95,6 +97,7 @@
                 statusBarModeRepositoryStore.forDisplay(displayId),
                 initializerStore.forDisplay(displayId),
                 statusBarWindowControllerStore.forDisplay(displayId),
+                autoHideControllerStore.forDisplay(displayId),
             )
             .start()
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarOrchestrator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarOrchestrator.kt
index ff4760f..9f5a311 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarOrchestrator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarOrchestrator.kt
@@ -71,9 +71,9 @@
     @Assisted private val statusBarInitializer: StatusBarInitializer,
     @Assisted private val statusBarWindowController: StatusBarWindowController,
     @Main private val mainContext: CoroutineContext,
+    @Assisted private val autoHideController: AutoHideController,
     private val demoModeController: DemoModeController,
     private val pluginDependencyProvider: PluginDependencyProvider,
-    private val autoHideController: AutoHideController,
     private val remoteInputManager: NotificationRemoteInputManager,
     private val notificationShadeWindowViewControllerLazy:
         Lazy<NotificationShadeWindowViewController>,
@@ -210,10 +210,6 @@
     }
 
     private fun setUpAutoHide() {
-        if (displayId != Display.DEFAULT_DISPLAY) {
-            return
-        }
-        // TODO(b/373309973): per display implementation of auto hide controller
         autoHideController.setStatusBar(
             object : AutoHideUiElement {
                 override fun synchronizeState() {}
@@ -241,10 +237,7 @@
         if (!demoModeController.isInDemoMode) {
             barTransitions.transitionTo(barMode.toTransitionModeInt(), animate)
         }
-        if (displayId == Display.DEFAULT_DISPLAY) {
-            // TODO(b/373309973): per display implementation of auto hide controller
-            autoHideController.touchAutoHide()
-        }
+        autoHideController.touchAutoHide()
     }
 
     private fun updateBubblesVisibility(statusBarVisible: Boolean) {
@@ -288,6 +281,7 @@
             statusBarModeRepository: StatusBarModePerDisplayRepository,
             statusBarInitializer: StatusBarInitializer,
             statusBarWindowController: StatusBarWindowController,
+            autoHideController: AutoHideController,
         ): StatusBarOrchestrator
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
index 4341200..47b695e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
@@ -27,7 +27,10 @@
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import com.android.systemui.statusbar.data.StatusBarDataLayerModule
 import com.android.systemui.statusbar.data.repository.LightBarControllerStore
+import com.android.systemui.statusbar.phone.AutoHideController
+import com.android.systemui.statusbar.phone.AutoHideControllerImpl
 import com.android.systemui.statusbar.phone.LightBarController
+import com.android.systemui.statusbar.phone.LightBarControllerImpl
 import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
 import com.android.systemui.statusbar.phone.StatusBarContentInsetsProviderImpl
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy
@@ -79,6 +82,13 @@
         implFactory: StatusBarWindowControllerImpl.Factory
     ): StatusBarWindowController.Factory
 
+    @Binds @SysUISingleton fun autoHideController(impl: AutoHideControllerImpl): AutoHideController
+
+    @Binds
+    fun lightBarControllerFactory(
+        legacyFactory: LightBarControllerImpl.LegacyFactory
+    ): LightBarController.Factory
+
     companion object {
 
         @Provides
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
index 9a779300..3825c09 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
@@ -34,12 +34,12 @@
 import com.android.systemui.statusbar.notification.collection.inflation.BindEventManager
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
+import com.android.systemui.statusbar.notification.headsup.OnHeadsUpChangedListener
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationContentView
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinderLogger
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator
-import com.android.systemui.statusbar.policy.HeadsUpManager
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
 import com.android.systemui.util.children
 import java.util.concurrent.ConcurrentHashMap
 import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
index b67092c..0569074 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
@@ -17,98 +17,16 @@
 package com.android.systemui.statusbar.notification
 
 import android.content.Context
-import android.provider.DeviceConfig
-import com.android.internal.annotations.VisibleForTesting
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.notification.collection.NotificationClassificationFlag
-import com.android.systemui.statusbar.notification.shared.NotificationMinimalism
-import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection
-import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
-import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE
-import com.android.systemui.statusbar.notification.stack.BUCKET_HEADS_UP
-import com.android.systemui.statusbar.notification.stack.BUCKET_MEDIA_CONTROLS
-import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE
-import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
-import com.android.systemui.statusbar.notification.stack.PriorityBucket
-import com.android.systemui.util.DeviceConfigProxy
 import com.android.systemui.util.Utils
 import javax.inject.Inject
 
-private var sUsePeopleFiltering: Boolean? = null
-
-/** Feature controller for the NOTIFICATIONS_USE_PEOPLE_FILTERING config. */
 @SysUISingleton
 class NotificationSectionsFeatureManager
 @Inject
-constructor(val proxy: DeviceConfigProxy, val context: Context) {
-
-    fun isFilteringEnabled(): Boolean {
-        return usePeopleFiltering(proxy)
-    }
+constructor(val context: Context) {
 
     fun isMediaControlsEnabled(): Boolean {
         return Utils.useQsMediaPlayer(context)
     }
-
-    fun getNotificationBuckets(): IntArray {
-        if (
-            PriorityPeopleSection.isEnabled ||
-                NotificationMinimalism.isEnabled ||
-                NotificationClassificationFlag.isEnabled
-        ) {
-            // We don't need this list to be adaptive, it can be the superset of all features.
-            return PriorityBucket.getAllInOrder()
-        }
-        return when {
-            isFilteringEnabled() && isMediaControlsEnabled() ->
-                intArrayOf(
-                    BUCKET_HEADS_UP,
-                    BUCKET_FOREGROUND_SERVICE,
-                    BUCKET_MEDIA_CONTROLS,
-                    BUCKET_PEOPLE,
-                    BUCKET_ALERTING,
-                    BUCKET_SILENT
-                )
-            !isFilteringEnabled() && isMediaControlsEnabled() ->
-                intArrayOf(
-                    BUCKET_HEADS_UP,
-                    BUCKET_FOREGROUND_SERVICE,
-                    BUCKET_MEDIA_CONTROLS,
-                    BUCKET_ALERTING,
-                    BUCKET_SILENT
-                )
-            isFilteringEnabled() && !isMediaControlsEnabled() ->
-                intArrayOf(
-                    BUCKET_HEADS_UP,
-                    BUCKET_FOREGROUND_SERVICE,
-                    BUCKET_PEOPLE,
-                    BUCKET_ALERTING,
-                    BUCKET_SILENT
-                )
-            else -> intArrayOf(BUCKET_ALERTING, BUCKET_SILENT)
-        }
-    }
-
-    fun getNumberOfBuckets(): Int {
-        return getNotificationBuckets().size
-    }
-
-    @VisibleForTesting
-    fun clearCache() {
-        sUsePeopleFiltering = null
-    }
-}
-
-private fun usePeopleFiltering(proxy: DeviceConfigProxy): Boolean {
-    if (sUsePeopleFiltering == null) {
-        sUsePeopleFiltering =
-            proxy.getBoolean(
-                DeviceConfig.NAMESPACE_SYSTEMUI,
-                NOTIFICATIONS_USE_PEOPLE_FILTERING,
-                true
-            )
-    }
-
-    return sUsePeopleFiltering!!
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorController.kt
index 67c53d46..383227d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorController.kt
@@ -22,10 +22,10 @@
 import com.android.systemui.animation.ActivityTransitionAnimator
 import com.android.systemui.animation.TransitionAnimator
 import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
+import com.android.systemui.statusbar.notification.headsup.HeadsUpUtil
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
-import com.android.systemui.statusbar.policy.HeadsUpManager
-import com.android.systemui.statusbar.policy.HeadsUpUtil
 import kotlin.math.ceil
 import kotlin.math.max
 
@@ -36,12 +36,12 @@
     private val notificationLaunchAnimationInteractor: NotificationLaunchAnimationInteractor,
     private val notificationListContainer: NotificationListContainer,
     private val headsUpManager: HeadsUpManager,
-    private val jankMonitor: InteractionJankMonitor
+    private val jankMonitor: InteractionJankMonitor,
 ) {
     @JvmOverloads
     fun getAnimatorController(
         notification: ExpandableNotificationRow,
-        onFinishAnimationCallback: Runnable? = null
+        onFinishAnimationCallback: Runnable? = null,
     ): NotificationTransitionAnimatorController {
         return NotificationTransitionAnimatorController(
             notificationLaunchAnimationInteractor,
@@ -49,7 +49,7 @@
             headsUpManager,
             notification,
             jankMonitor,
-            onFinishAnimationCallback
+            onFinishAnimationCallback,
         )
     }
 }
@@ -65,7 +65,7 @@
     private val headsUpManager: HeadsUpManager,
     private val notification: ExpandableNotificationRow,
     private val jankMonitor: InteractionJankMonitor,
-    private val onFinishAnimationCallback: Runnable?
+    private val onFinishAnimationCallback: Runnable?,
 ) : ActivityTransitionAnimator.Controller {
 
     companion object {
@@ -109,7 +109,7 @@
                 left = location[0],
                 right = location[0] + notification.width,
                 topCornerRadius = topCornerRadius,
-                bottomCornerRadius = notification.bottomCornerRadius
+                bottomCornerRadius = notification.bottomCornerRadius,
             )
 
         params.startTranslationZ = notification.translationZ
@@ -177,7 +177,7 @@
             row.entry.key,
             true /* releaseImmediately */,
             animate,
-            reason
+            reason,
         )
     }
 
@@ -224,7 +224,7 @@
     override fun onTransitionAnimationProgress(
         state: TransitionAnimator.State,
         progress: Float,
-        linearProgress: Float
+        linearProgress: Float,
     ) {
         val params = state as LaunchAnimationParameters
         params.progress = progress
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 08ffbf2..7a59f79 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -36,14 +36,14 @@
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
+import com.android.systemui.statusbar.notification.headsup.OnHeadsUpChangedListener
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator
 import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.phone.KeyguardBypassController.OnBypassStateChangedListener
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController
-import com.android.systemui.statusbar.policy.HeadsUpManager
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
 import com.android.systemui.util.doOnEnd
 import com.android.systemui.util.doOnStart
 import java.io.PrintWriter
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index c487ff5..6b84b6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -65,6 +65,7 @@
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
+import com.android.systemui.statusbar.notification.headsup.PinnedStatus;
 import com.android.systemui.statusbar.notification.icon.IconPack;
 import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -675,8 +676,8 @@
         return row != null && row.isPinnedAndExpanded();
     }
 
-    public void setRowPinned(boolean pinned) {
-        if (row != null) row.setPinned(pinned);
+    public void setRowPinnedStatus(PinnedStatus pinnedStatus) {
+        if (row != null) row.setPinnedStatus(pinnedStatus);
     }
 
     public boolean isRowHeadsUp() {
@@ -1075,7 +1076,7 @@
         if (PromotedNotificationContentModel.featureFlagEnabled()) {
             return mPromotedNotificationContentModel;
         } else {
-            Log.wtf(TAG, "getting promoted content without feature flag enabled");
+            Log.wtf(TAG, "getting promoted content without feature flag enabled", new Throwable());
             return null;
         }
     }
@@ -1089,7 +1090,7 @@
         if (PromotedNotificationContentModel.featureFlagEnabled()) {
             this.mPromotedNotificationContentModel = promotedNotificationContentModel;
         } else {
-            Log.wtf(TAG, "setting promoted content without feature flag enabled");
+            Log.wtf(TAG, "setting promoted content without feature flag enabled", new Throwable());
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java
index 47a0429..733b986 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java
@@ -20,13 +20,21 @@
 
 import android.app.Notification;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import com.android.systemui.statusbar.notification.collection.ListEntry;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi;
 import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
 
+import com.google.common.primitives.Booleans;
+
 import javax.inject.Inject;
 
 /**
@@ -44,12 +52,21 @@
 
     @Override
     public void attach(NotifPipeline pipeline) {
+        if (PromotedNotificationUi.isEnabled()) {
+            pipeline.addPromoter(mPromotedOngoingPromoter);
+        }
     }
 
     public NotifSectioner getSectioner() {
         return mNotifSectioner;
     }
 
+    private final NotifPromoter mPromotedOngoingPromoter = new NotifPromoter("PromotedOngoing") {
+        @Override
+        public boolean shouldPromoteToTopLevel(NotificationEntry child) {
+            return isPromotedOngoing(child);
+        }
+    };
 
     /**
      * Puts colorized foreground service and call notifications into its own section.
@@ -64,11 +81,30 @@
             }
             return false;
         }
+
+        private NotifComparator mPreferPromoted = new NotifComparator("PreferPromoted") {
+            @Override
+            public int compare(@NonNull ListEntry o1, @NonNull ListEntry o2) {
+                return -1 * Booleans.compare(
+                        isPromotedOngoing(o1.getRepresentativeEntry()),
+                        isPromotedOngoing(o2.getRepresentativeEntry()));
+            }
+        };
+
+        @Nullable
+        @Override
+        public NotifComparator getComparator() {
+            if (PromotedNotificationUi.isEnabled()) {
+                return mPreferPromoted;
+            } else {
+                return null;
+            }
+        }
     };
 
     /** Determines if the given notification is a colorized or call notification */
     public static boolean isRichOngoing(NotificationEntry entry) {
-        return isColorizedForegroundService(entry) || isCall(entry);
+        return isPromotedOngoing(entry) || isColorizedForegroundService(entry) || isCall(entry);
     }
 
     private static boolean isColorizedForegroundService(NotificationEntry entry) {
@@ -78,6 +114,11 @@
                 && entry.getImportance() > IMPORTANCE_MIN;
     }
 
+    private static boolean isPromotedOngoing(NotificationEntry entry) {
+        // NOTE: isPromotedOngoing already checks the android.app.ui_rich_ongoing flag.
+        return entry != null && entry.getSbn().getNotification().isPromotedOngoing();
+    }
+
     private static boolean isCall(NotificationEntry entry) {
         Notification notification = entry.getSbn().getNotification();
         return entry.getImportance() > IMPORTANCE_MIN
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
index c7b47ee..0269b16 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
@@ -41,13 +41,13 @@
 import com.android.systemui.statusbar.notification.collection.provider.LaunchFullScreenIntentProvider
 import com.android.systemui.statusbar.notification.collection.render.NodeController
 import com.android.systemui.statusbar.notification.dagger.IncomingHeader
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
+import com.android.systemui.statusbar.notification.headsup.OnHeadsUpChangedListener
 import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider
 import com.android.systemui.statusbar.notification.logKey
 import com.android.systemui.statusbar.notification.shared.GroupHunAnimationFix
 import com.android.systemui.statusbar.notification.stack.BUCKET_HEADS_UP
-import com.android.systemui.statusbar.policy.HeadsUpManager
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
 import com.android.systemui.util.concurrency.DelayableExecutor
 import com.android.systemui.util.time.SystemClock
 import java.util.function.Consumer
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinator.kt
index 366704e..de6f257 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinator.kt
@@ -18,6 +18,7 @@
 
 import android.annotation.SuppressLint
 import androidx.annotation.VisibleForTesting
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.Dumpable
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dump.DumpManager
@@ -35,8 +36,8 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
 import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor
-import com.android.systemui.statusbar.policy.HeadsUpManager
-import com.android.systemui.statusbar.policy.headsUpEvents
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
+import com.android.systemui.statusbar.notification.headsup.headsUpEvents
 import com.android.systemui.util.asIndenting
 import com.android.systemui.util.indentIfPossible
 import java.io.PrintWriter
@@ -52,7 +53,6 @@
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
-import com.android.app.tracing.coroutines.launchTraced as launch
 import kotlinx.coroutines.yield
 
 /**
@@ -123,7 +123,7 @@
                     unseenNotifications.removeAll(notificationsSeenWhileLocked)
                     logger.logAllMarkedSeenOnUnlock(
                         seenCount = notificationsSeenWhileLocked.size,
-                        remainingUnseenCount = unseenNotifications.size
+                        remainingUnseenCount = unseenNotifications.size,
                     )
                     notificationsSeenWhileLocked.clear()
                 }
@@ -140,7 +140,7 @@
      * been "seen" while the device is on the keyguard.
      */
     private suspend fun trackSeenNotificationsWhileLocked(
-        notificationsSeenWhileLocked: MutableSet<NotificationEntry>,
+        notificationsSeenWhileLocked: MutableSet<NotificationEntry>
     ) = coroutineScope {
         // Remove removed notifications from the set
         launch {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
index 8660cd1..e75c11d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
@@ -45,7 +45,7 @@
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
 import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor;
 import com.android.systemui.statusbar.notification.shared.NotificationMinimalism;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.kotlin.BooleanFlowOperators;
 import com.android.systemui.util.kotlin.JavaAdapter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java
index 5743ab0..07fa6ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java
@@ -34,7 +34,7 @@
 import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
 import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 
 import javax.inject.Inject;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 42aadd1..8a1371f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -77,6 +77,10 @@
 import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
 import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerImpl;
 import com.android.systemui.statusbar.notification.logging.dagger.NotificationsLogModule;
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor;
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationLogger;
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationsProvider;
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel;
 import com.android.systemui.statusbar.notification.row.NotificationEntryProcessorFactory;
 import com.android.systemui.statusbar.notification.row.NotificationEntryProcessorFactoryLooperImpl;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -88,7 +92,7 @@
 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.policy.ZenModesCleanupStartable;
 
 import dagger.Binds;
@@ -101,6 +105,8 @@
 
 import kotlinx.coroutines.CoroutineScope;
 
+import java.util.Optional;
+
 import javax.inject.Provider;
 
 /**
@@ -308,4 +314,22 @@
     @IntoMap
     @ClassKey(ZenModesCleanupStartable.class)
     CoreStartable bindsZenModesCleanup(ZenModesCleanupStartable zenModesCleanup);
+
+    /**
+     * Provides {@link
+     * com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor} if
+     * one of the relevant feature flags is enabled.
+     */
+    @Provides
+    @SysUISingleton
+    static Optional<PromotedNotificationContentExtractor>
+            providePromotedNotificationContentExtractor(
+                    PromotedNotificationsProvider provider, Context context,
+                    PromotedNotificationLogger logger) {
+        if (PromotedNotificationContentModel.featureFlagEnabled()) {
+            return Optional.of(new PromotedNotificationContentExtractor(provider, context, logger));
+        } else {
+            return Optional.empty();
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
index cf4fb25..3759835 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
@@ -16,11 +16,11 @@
 package com.android.systemui.statusbar.notification.data
 
 import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository
-import com.android.systemui.statusbar.policy.BaseHeadsUpManager
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManagerImpl
 import dagger.Binds
 import dagger.Module
 
 @Module(includes = [NotificationSettingsRepositoryModule::class])
 interface NotificationDataLayerModule {
-    @Binds fun bindHeadsUpNotificationRepository(impl: BaseHeadsUpManager): HeadsUpRepository
+    @Binds fun bindHeadsUpNotificationRepository(impl: HeadsUpManagerImpl): HeadsUpRepository
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpRowRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpRowRepository.kt
index 7b40812..2663104 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpRowRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpRowRepository.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.data.repository
 
+import com.android.systemui.statusbar.notification.headsup.PinnedStatus
 import com.android.systemui.statusbar.notification.shared.HeadsUpRowKey
 import kotlinx.coroutines.flow.StateFlow
 
@@ -31,6 +32,6 @@
     /** A key to identify this row in the view hierarchy. */
     val elementKey: Any
 
-    /** Whether this notification is "pinned", meaning that it should stay on top of the screen. */
-    val isPinned: StateFlow<Boolean>
+    /** This notification's pinning status. */
+    val pinnedStatus: StateFlow<PinnedStatus>
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt
index e25127e..64e78e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt
@@ -52,7 +52,9 @@
     val topHeadsUpRowIfPinned: Flow<HeadsUpRowKey?> =
         headsUpRepository.topHeadsUpRow
             .flatMapLatest { repository ->
-                repository?.isPinned?.map { pinned -> repository.takeIf { pinned } } ?: flowOf(null)
+                repository?.pinnedStatus?.map { pinnedStatus ->
+                    repository.takeIf { pinnedStatus.isPinned }
+                } ?: flowOf(null)
             }
             .distinctUntilChanged()
 
@@ -64,7 +66,7 @@
                 if (repositories.isNotEmpty()) {
                     val toCombine: List<Flow<Pair<HeadsUpRowRepository, Boolean>>> =
                         repositories.map { repo ->
-                            repo.isPinned.map { isPinned -> repo to isPinned }
+                            repo.pinnedStatus.map { pinnedStatus -> repo to pinnedStatus.isPinned }
                         }
                     combine(toCombine) { pairs -> pairs.toSet() }
                 } else {
@@ -96,20 +98,17 @@
     }
 
     /** Are there any pinned heads up rows to display? */
-    val hasPinnedRows: Flow<Boolean> by lazy {
-        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
-            flowOf(false)
-        } else {
-            headsUpRepository.activeHeadsUpRows.flatMapLatest { rows ->
-                if (rows.isNotEmpty()) {
-                    combine(rows.map { it.isPinned }) { pins -> pins.any { it } }
-                } else {
-                    // if the set is empty, there are no flows to combine
-                    flowOf(false)
+    val hasPinnedRows: Flow<Boolean> =
+        headsUpRepository.activeHeadsUpRows.flatMapLatest { rows ->
+            if (rows.isNotEmpty()) {
+                combine(rows.map { it.pinnedStatus }) { pinnedStatus ->
+                    pinnedStatus.any { it.isPinned }
                 }
+            } else {
+                // if the set is empty, there are no flows to combine
+                flowOf(false)
             }
         }
-    }
 
     val isHeadsUpOrAnimatingAway: Flow<Boolean> by lazy {
         if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
@@ -139,15 +138,10 @@
             }
         }
 
-    val showHeadsUpStatusBar: Flow<Boolean> by lazy {
-        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
-            flowOf(false)
-        } else {
-            combine(hasPinnedRows, canShowHeadsUp) { hasPinnedRows, canShowHeadsUp ->
-                hasPinnedRows && canShowHeadsUp
-            }
+    val showHeadsUpStatusBar =
+        combine(hasPinnedRows, canShowHeadsUp) { hasPinnedRows, canShowHeadsUp ->
+            hasPinnedRows && canShowHeadsUp
         }
-    }
 
     fun headsUpRow(key: HeadsUpRowKey): HeadsUpRowInteractor =
         HeadsUpRowInteractor(key as HeadsUpRowRepository)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
index 8edbc5e..8bd7a1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
@@ -152,6 +152,13 @@
             } else {
                 null
             }
+        val promotedContent =
+            if (PromotedNotificationContentModel.featureFlagEnabled()) {
+                promotedNotificationContentModel
+            } else {
+                null
+            }
+
         return existingModels.createOrReuse(
             key = key,
             groupKey = sbn.groupKey,
@@ -174,7 +181,7 @@
             isGroupSummary = sbn.notification.isGroupSummary,
             bucket = bucket,
             callType = sbn.toCallType(),
-            promotedContent = promotedNotificationContentModel,
+            promotedContent = promotedContent,
         )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt
similarity index 90%
rename from packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt
index d406ed4..5c7c020 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.statusbar.policy
+package com.android.systemui.statusbar.notification.headsup
 
 import android.os.Handler
 import android.util.Log
@@ -24,29 +24,30 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManagerImpl.HeadsUpEntry
 import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
-import com.android.systemui.statusbar.policy.BaseHeadsUpManager.HeadsUpEntry
 import com.android.systemui.util.Compile
 import java.io.PrintWriter
 import javax.inject.Inject
 
 /*
  * Control when heads up notifications show during an avalanche where notifications arrive in fast
- * succession, by delaying visual listener side effects and removal handling from BaseHeadsUpManager
+ * succession, by delaying visual listener side effects and removal handling from
+ * [HeadsUpManagerImpl].
  */
 @SysUISingleton
 class AvalancheController
 @Inject
 constructor(
-        dumpManager: DumpManager,
-        private val uiEventLogger: UiEventLogger,
-        private val headsUpManagerLogger: HeadsUpManagerLogger,
-        @Background private val bgHandler: Handler
+    dumpManager: DumpManager,
+    private val uiEventLogger: UiEventLogger,
+    private val headsUpManagerLogger: HeadsUpManagerLogger,
+    @Background private val bgHandler: Handler,
 ) : Dumpable {
 
     private val tag = "AvalancheController"
     private val debug = Compile.IS_DEBUG && Log.isLoggable(tag, Log.DEBUG)
-    var baseEntryMapStr : () -> String = { "baseEntryMapStr not initialized" }
+    var baseEntryMapStr: () -> String = { "baseEntryMapStr not initialized" }
 
     var enableAtRuntime = true
         set(value) {
@@ -119,23 +120,29 @@
 
         if (runnable == null) {
             headsUpManagerLogger.logAvalancheUpdate(
-                caller, isEnabled, key,
-                "Runnable NULL, stop. ${getStateStr()}"
+                caller,
+                isEnabled,
+                key,
+                "Runnable NULL, stop. ${getStateStr()}",
             )
             return
         }
         if (!isEnabled) {
             headsUpManagerLogger.logAvalancheUpdate(
-                caller, isEnabled, key,
-                "NOT ENABLED, run runnable. ${getStateStr()}"
+                caller,
+                isEnabled,
+                key,
+                "NOT ENABLED, run runnable. ${getStateStr()}",
             )
             runnable.run()
             return
         }
         if (entry == null) {
             headsUpManagerLogger.logAvalancheUpdate(
-                caller, isEnabled, key,
-                "Entry NULL, stop. ${getStateStr()}"
+                caller,
+                isEnabled,
+                key,
+                "Entry NULL, stop. ${getStateStr()}",
             )
             return
         }
@@ -168,7 +175,7 @@
                 headsUpEntryShowing!!.updateEntry(
                     /* updatePostTime= */ false,
                     /* updateEarliestRemovalTime= */ false,
-                    /* reason= */ "avalanche duration update"
+                    /* reason= */ "avalanche duration update",
                 )
             }
         }
@@ -192,24 +199,30 @@
 
         if (runnable == null) {
             headsUpManagerLogger.logAvalancheDelete(
-                caller, isEnabled, key,
-                "Runnable NULL, stop. ${getStateStr()}"
+                caller,
+                isEnabled,
+                key,
+                "Runnable NULL, stop. ${getStateStr()}",
             )
             return
         }
         if (!isEnabled) {
             runnable.run()
             headsUpManagerLogger.logAvalancheDelete(
-                caller, isEnabled = false, key,
-                "NOT ENABLED, run runnable. ${getStateStr()}"
+                caller,
+                isEnabled = false,
+                key,
+                "NOT ENABLED, run runnable. ${getStateStr()}",
             )
             return
         }
         if (entry == null) {
             runnable.run()
             headsUpManagerLogger.logAvalancheDelete(
-                caller, isEnabled = true, key,
-                "Entry NULL, run runnable. ${getStateStr()}"
+                caller,
+                isEnabled = true,
+                key,
+                "Entry NULL, run runnable. ${getStateStr()}",
             )
             return
         }
@@ -219,11 +232,9 @@
             if (entry in nextList) nextList.remove(entry)
             uiEventLogger.log(ThrottleEvent.AVALANCHE_THROTTLING_HUN_REMOVED)
             outcome = "remove from next. ${getStateStr()}"
-
         } else if (entry in debugDropSet) {
             debugDropSet.remove(entry)
             outcome = "remove from dropset. ${getStateStr()}"
-
         } else if (isShowing(entry)) {
             previousHunKey = getKey(headsUpEntryShowing)
             // Show the next HUN before removing this one, so that we don't tell listeners
@@ -233,7 +244,6 @@
             showNext()
             runnable.run()
             outcome = "remove showing. ${getStateStr()}"
-
         } else {
             runnable.run()
             outcome = "run runnable for untracked shown HUN. ${getStateStr()}"
@@ -421,13 +431,13 @@
 
     private fun getStateStr(): String {
         return "\navalanche state:" +
-                "\n\tshowing: [${getKey(headsUpEntryShowing)}]" +
-                "\n\tprevious: [$previousHunKey]" +
-                "\n\tnext list: $nextListStr" +
-                "\n\tnext map: $nextMapStr" +
-                "\n\tdropped: $dropSetStr" +
-                "\nBHUM.mHeadsUpEntryMap: " +
-                baseEntryMapStr()
+            "\n\tshowing: [${getKey(headsUpEntryShowing)}]" +
+            "\n\tprevious: [$previousHunKey]" +
+            "\n\tnext list: $nextListStr" +
+            "\n\tnext map: $nextMapStr" +
+            "\n\tdropped: $dropSetStr" +
+            "\nBHUM.mHeadsUpEntryMap: " +
+            baseEntryMapStr()
     }
 
     private val dropSetStr: String
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManager.kt
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManager.kt
index b37194b..424a3c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManager.kt
@@ -1,4 +1,20 @@
-package com.android.systemui.statusbar.policy
+/*
+ * 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.statusbar.notification.headsup
 
 import android.graphics.Region
 import com.android.systemui.Dumpable
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerExt.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerExt.kt
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerExt.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerExt.kt
index 5e36750..6525b6f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerExt.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerExt.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.policy
+package com.android.systemui.statusbar.notification.headsup
 
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
index 298ef7e..99df9f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.policy;
+package com.android.systemui.statusbar.notification.headsup;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -55,6 +55,8 @@
 import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
 import com.android.systemui.statusbar.phone.ExpandHeadsUpOnInlineReply;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.util.ListenerSet;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.kotlin.JavaAdapter;
@@ -84,7 +86,7 @@
  * they simply peek from the top of the screen.
  */
 @SysUISingleton
-public class BaseHeadsUpManager
+public class HeadsUpManagerImpl
         implements HeadsUpManager, HeadsUpRepository, OnHeadsUpChangedListener {
     private static final String TAG = "BaseHeadsUpManager";
     private static final String SETTING_HEADS_UP_SNOOZE_LENGTH_MS = "heads_up_snooze_length_ms";
@@ -180,7 +182,7 @@
     }
 
     @Inject
-    public BaseHeadsUpManager(
+    public HeadsUpManagerImpl(
             @NonNull final Context context,
             HeadsUpManagerLogger logger,
             StatusBarStateController statusBarStateController,
@@ -403,9 +405,11 @@
         }
         if (shouldHeadsUpAgain) {
             headsUpEntry.updateEntry(true /* updatePostTime */, "updateNotification");
+            PinnedStatus pinnedStatus = shouldHeadsUpBecomePinned(headsUpEntry.mEntry)
+                    ? PinnedStatus.PinnedBySystem
+                    : PinnedStatus.NotPinned;
             if (headsUpEntry != null) {
-                setEntryPinned(headsUpEntry, shouldHeadsUpBecomePinned(headsUpEntry.mEntry),
-                        "updateNotificationInternal");
+                setEntryPinned(headsUpEntry, pinnedStatus, "updateNotificationInternal");
             }
         }
     }
@@ -417,7 +421,7 @@
 
     @Override
     public boolean shouldSwallowClick(@NonNull String key) {
-        BaseHeadsUpManager.HeadsUpEntry entry = getHeadsUpEntry(key);
+        HeadsUpManagerImpl.HeadsUpEntry entry = getHeadsUpEntry(key);
         return entry != null && mSystemClock.elapsedRealtime() < entry.mPostTime;
     }
 
@@ -560,15 +564,16 @@
     }
 
     protected void setEntryPinned(
-            @NonNull BaseHeadsUpManager.HeadsUpEntry headsUpEntry, boolean isPinned,
+            @NonNull HeadsUpManagerImpl.HeadsUpEntry headsUpEntry, PinnedStatus pinnedStatus,
             String reason) {
-        mLogger.logSetEntryPinned(headsUpEntry.mEntry, isPinned, reason);
+        mLogger.logSetEntryPinned(headsUpEntry.mEntry, pinnedStatus, reason);
         NotificationEntry entry = headsUpEntry.mEntry;
+        boolean isPinned = pinnedStatus.isPinned();
         if (!isPinned) {
             headsUpEntry.mWasUnpinned = true;
         }
-        if (headsUpEntry.isRowPinned() != isPinned) {
-            headsUpEntry.setRowPinned(isPinned);
+        if (headsUpEntry.getPinnedStatus().getValue() != pinnedStatus) {
+            headsUpEntry.setRowPinnedStatus(pinnedStatus);
             updatePinnedMode();
             if (isPinned && entry.getSbn() != null) {
                mUiEventLogger.logWithInstanceId(
@@ -594,8 +599,10 @@
         NotificationEntry entry = headsUpEntry.mEntry;
         entry.setHeadsUp(true);
 
-        final boolean shouldPin = shouldHeadsUpBecomePinned(entry);
-        setEntryPinned(headsUpEntry, shouldPin, "onEntryAdded");
+        final PinnedStatus pinnedStatus = shouldHeadsUpBecomePinned(entry)
+                ? PinnedStatus.PinnedBySystem
+                : PinnedStatus.NotPinned;
+        setEntryPinned(headsUpEntry, pinnedStatus, "onEntryAdded");
         EventLogTags.writeSysuiHeadsUpStatus(entry.getKey(), 1 /* visible */);
         for (OnHeadsUpChangedListener listener : mListeners) {
             listener.onHeadsUpStateChanged(entry, true);
@@ -653,7 +660,7 @@
     protected void onEntryRemoved(HeadsUpEntry headsUpEntry, String reason) {
         NotificationEntry entry = headsUpEntry.mEntry;
         entry.setHeadsUp(false);
-        setEntryPinned(headsUpEntry, false /* isPinned */, "onEntryRemoved");
+        setEntryPinned(headsUpEntry, PinnedStatus.NotPinned, "onEntryRemoved");
         EventLogTags.writeSysuiHeadsUpStatus(entry.getKey(), 0 /* visible */);
         mLogger.logNotificationActuallyRemoved(entry);
         for (OnHeadsUpChangedListener listener : mListeners) {
@@ -962,7 +969,7 @@
             Runnable runnable = () -> {
                 mLogger.logUnpinEntry(key);
 
-                setEntryPinned(headsUpEntry, false /* isPinned */, "unpinAll");
+                setEntryPinned(headsUpEntry, PinnedStatus.NotPinned, "unpinAll");
                 // maybe it got un sticky
                 headsUpEntry.updateEntry(false /* updatePostTime */, "unpinAll");
 
@@ -1233,7 +1240,8 @@
         @Nullable private Runnable mCancelRemoveRunnable;
 
         private boolean mGutsShownPinned;
-        private final MutableStateFlow<Boolean> mIsPinned = StateFlowKt.MutableStateFlow(false);
+        private final MutableStateFlow<PinnedStatus> mPinnedStatus =
+                StateFlowKt.MutableStateFlow(PinnedStatus.NotPinned);
 
         /**
          * If the time this entry has been on was extended
@@ -1269,8 +1277,8 @@
 
         @Override
         @NonNull
-        public StateFlow<Boolean> isPinned() {
-            return mIsPinned;
+        public StateFlow<PinnedStatus> getPinnedStatus() {
+            return mPinnedStatus;
         }
 
         /** Attach a NotificationEntry. */
@@ -1300,9 +1308,9 @@
             return mEntry != null && mEntry.isRowPinned();
         }
 
-        protected void setRowPinned(boolean pinned) {
-            if (mEntry != null) mEntry.setRowPinned(pinned);
-            mIsPinned.setValue(pinned);
+        protected void setRowPinnedStatus(PinnedStatus pinnedStatus) {
+            if (mEntry != null) mEntry.setRowPinnedStatus(pinnedStatus);
+            mPinnedStatus.setValue(pinnedStatus);
         }
 
         /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt
similarity index 90%
rename from packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt
index 600270c..80225c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.policy
+package com.android.systemui.statusbar.notification.headsup
 
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.LogLevel.INFO
@@ -52,7 +52,7 @@
         caller: String,
         isEnabled: Boolean,
         notifEntryKey: String,
-        outcome: String
+        outcome: String,
     ) {
         buffer.log(
             TAG,
@@ -63,7 +63,7 @@
                 str3 = outcome
                 bool1 = isEnabled
             },
-            { "$str1\n\t=> AC[isEnabled:$bool1] update: $str2\n\t=> $str3" }
+            { "$str1\n\t=> AC[isEnabled:$bool1] update: $str2\n\t=> $str3" },
         )
     }
 
@@ -71,7 +71,7 @@
         caller: String,
         isEnabled: Boolean,
         notifEntryKey: String,
-        outcome: String
+        outcome: String,
     ) {
         buffer.log(
             TAG,
@@ -82,7 +82,7 @@
                 str3 = outcome
                 bool1 = isEnabled
             },
-            { "$str1\n\t=> AC[isEnabled:$bool1] delete: $str2\n\t=> $str3" }
+            { "$str1\n\t=> AC[isEnabled:$bool1] delete: $str2\n\t=> $str3" },
         )
     }
 
@@ -99,7 +99,7 @@
                 long1 = delayMillis
                 str2 = reason
             },
-            { "schedule auto remove of $str1 in $long1 ms reason: $str2" }
+            { "schedule auto remove of $str1 in $long1 ms reason: $str2" },
         )
     }
 
@@ -111,7 +111,7 @@
                 str1 = entry.logKey
                 str2 = reason
             },
-            { "request: reschedule auto remove of $str1 reason: $str2" }
+            { "request: reschedule auto remove of $str1 reason: $str2" },
         )
     }
 
@@ -124,7 +124,7 @@
                 long1 = delayMillis
                 str2 = reason
             },
-            { "reschedule auto remove of $str1 in $long1 ms reason: $str2" }
+            { "reschedule auto remove of $str1 in $long1 ms reason: $str2" },
         )
     }
 
@@ -136,7 +136,7 @@
                 str1 = entry.logKey
                 str2 = reason ?: "unknown"
             },
-            { "request: cancel auto remove of $str1 reason: $str2" }
+            { "request: cancel auto remove of $str1 reason: $str2" },
         )
     }
 
@@ -148,7 +148,7 @@
                 str1 = entry.logKey
                 str2 = reason ?: "unknown"
             },
-            { "cancel auto remove of $str1 reason: $str2" }
+            { "cancel auto remove of $str1 reason: $str2" },
         )
     }
 
@@ -161,7 +161,7 @@
                 str2 = reason
                 bool1 = isWaiting
             },
-            { "request: $str2 => remove entry $str1 isWaiting: $isWaiting" }
+            { "request: $str2 => remove entry $str1 isWaiting: $isWaiting" },
         )
     }
 
@@ -174,7 +174,7 @@
                 str2 = reason
                 bool1 = isWaiting
             },
-            { "$str2 => remove entry $str1 isWaiting: $isWaiting" }
+            { "$str2 => remove entry $str1 isWaiting: $isWaiting" },
         )
     }
 
@@ -190,7 +190,7 @@
         key: String,
         releaseImmediately: Boolean,
         isWaiting: Boolean,
-        reason: String
+        reason: String,
     ) {
         buffer.log(
             TAG,
@@ -204,7 +204,7 @@
             {
                 "remove notification $str1 releaseImmediately: $bool1 isWaiting: $bool2 " +
                     "reason: $str2"
-            }
+            },
         )
     }
 
@@ -216,7 +216,7 @@
                 str1 = logKey(key)
                 str2 = reason
             },
-            { "remove notification $str1 when headsUpEntry is null, reason: $str2" }
+            { "remove notification $str1 when headsUpEntry is null, reason: $str2" },
         )
     }
 
@@ -233,7 +233,7 @@
                 bool1 = alert
                 bool2 = hasEntry
             },
-            { "request: update notification $str1 alert: $bool1 hasEntry: $bool2" }
+            { "request: update notification $str1 alert: $bool1 hasEntry: $bool2" },
         )
     }
 
@@ -246,7 +246,7 @@
                 bool1 = alert
                 bool2 = hasEntry
             },
-            { "update notification $str1 alert: $bool1 hasEntry: $bool2" }
+            { "update notification $str1 alert: $bool1 hasEntry: $bool2" },
         )
     }
 
@@ -259,7 +259,7 @@
                 bool1 = updatePostTime
                 str2 = reason ?: "unknown"
             },
-            { "update entry $str1 updatePostTime: $bool1 reason: $str2" }
+            { "update entry $str1 updatePostTime: $bool1 reason: $str2" },
         )
     }
 
@@ -268,20 +268,20 @@
             TAG,
             INFO,
             { int1 = packageSnoozeLengthMs },
-            { "snooze length changed: ${int1}ms" }
+            { "snooze length changed: ${int1}ms" },
         )
     }
 
-    fun logSetEntryPinned(entry: NotificationEntry, isPinned: Boolean, reason: String) {
+    fun logSetEntryPinned(entry: NotificationEntry, pinnedStatus: PinnedStatus, reason: String) {
         buffer.log(
             TAG,
             VERBOSE,
             {
                 str1 = entry.logKey
-                bool1 = isPinned
                 str2 = reason
+                str3 = pinnedStatus.name
             },
-            { "$str2 => set entry pinned $str1 pinned: $bool1" }
+            { "$str2 => set entry pinned $str1 pinned: $str3" },
         )
     }
 
@@ -290,16 +290,12 @@
             TAG,
             INFO,
             { bool1 = hasPinnedNotification },
-            { "has pinned notification changed to $bool1" }
+            { "has pinned notification changed to $bool1" },
         )
     }
 
     fun logRemoveEntryAfterExpand(entry: NotificationEntry) {
-        buffer.log(TAG, VERBOSE, {
-            str1 = entry.logKey
-        }, {
-            "remove entry after expand: $str1"
-        })
+        buffer.log(TAG, VERBOSE, { str1 = entry.logKey }, { "remove entry after expand: $str1" })
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpModule.kt
similarity index 74%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpModule.kt
index 83551e9..f9502ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpModule.kt
@@ -14,15 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.phone
+package com.android.systemui.statusbar.notification.headsup
 
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.policy.BaseHeadsUpManager
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import dagger.Binds
 import dagger.Module
 
 @Module
 interface HeadsUpModule {
-    @Binds @SysUISingleton fun bindsHeadsUpManager(hum: BaseHeadsUpManager): HeadsUpManager
+    @Binds @SysUISingleton fun bindsHeadsUpManager(hum: HeadsUpManagerImpl): HeadsUpManager
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpNotificationViewControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpNotificationViewControllerEmptyImpl.kt
similarity index 87%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpNotificationViewControllerEmptyImpl.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpNotificationViewControllerEmptyImpl.kt
index 021d301..84754e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpNotificationViewControllerEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpNotificationViewControllerEmptyImpl.kt
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification
+package com.android.systemui.statusbar.notification.headsup
 
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
-import com.android.systemui.statusbar.notification.HeadsUpTouchHelper.HeadsUpNotificationViewController
+import com.android.systemui.statusbar.notification.headsup.HeadsUpTouchHelper.HeadsUpNotificationViewController
 
 /** Empty impl of [HeadsUpNotificationViewController] for use with Scene Container */
 class HeadsUpNotificationViewControllerEmptyImpl : HeadsUpNotificationViewController {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpTouchHelper.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpTouchHelper.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpTouchHelper.java
index a614638..3b6b9ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpTouchHelper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification;
+package com.android.systemui.statusbar.notification.headsup;
 
 import android.content.Context;
 import android.os.RemoteException;
@@ -27,7 +27,6 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 /**
  * A helper class to handle touches on the heads-up views.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpUtil.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpUtil.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpUtil.java
index f4a1975..40da232 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpUtil.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.policy;
+package com.android.systemui.statusbar.notification.headsup;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/OnHeadsUpChangedListener.java
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/OnHeadsUpChangedListener.java
index de3bf04..b1fd784 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/OnHeadsUpChangedListener.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.policy;
+package com.android.systemui.statusbar.notification.headsup;
 
 import android.annotation.NonNull;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/PinnedStatus.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/PinnedStatus.kt
new file mode 100644
index 0000000..af18054
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/PinnedStatus.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.statusbar.notification.headsup
+
+/**
+ * A status representing whether and how a notification is pinned.
+ *
+ * @property isPinned true if a notification should be "pinned", meaning that a notification should
+ *   stay on top of the screen.
+ */
+enum class PinnedStatus(val isPinned: Boolean) {
+    /** This notification is not pinned. */
+    NotPinned(isPinned = false),
+    /**
+     * This notification is pinned by the system - likely because when the notification was added or
+     * updated, it required pinning.
+     */
+    PinnedBySystem(isPinned = true),
+    /**
+     * This notification is pinned because the user did an explicit action to pin it (like tapping
+     * the notification chip in the status bar).
+     */
+    // TODO(b/364653005): Use this status when a user taps the notification chip.
+    PinnedByUser(isPinned = true),
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/StatusBarHeadsUpChangeListener.java
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/StatusBarHeadsUpChangeListener.java
index 7145ffe..23eb507 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/StatusBarHeadsUpChangeListener.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.phone;
+package com.android.systemui.statusbar.notification.headsup;
 
 import com.android.systemui.CoreStartable;
 import com.android.systemui.dagger.SysUISingleton;
@@ -26,14 +26,13 @@
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
 
 import javax.inject.Inject;
 
 /**
- * Ties the status bar to {@link com.android.systemui.statusbar.policy.HeadsUpManager}.
+ * Ties the status bar to {@link HeadsUpManager}.
  */
 @SysUISingleton
 public class StatusBarHeadsUpChangeListener implements OnHeadsUpChangedListener, CoreStartable {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
index ec0827b..caa6ccf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
@@ -52,13 +52,13 @@
 import com.android.systemui.shared.notifications.domain.interactor.NotificationSettingsInteractor
 import com.android.systemui.statusbar.StatusBarState.SHADE
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.MAX_HUN_WHEN_AGE_MS
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.HUN_SUPPRESSED_OLD_WHEN
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.BUBBLE
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PEEK
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PULSE
 import com.android.systemui.statusbar.policy.BatteryController
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.util.NotificationChannels
 import com.android.systemui.util.settings.GlobalSettings
 import com.android.systemui.util.settings.SystemSettings
@@ -102,7 +102,7 @@
         globalSettings.registerContentObserverSync(
             globalSettings.getUriFor(HEADS_UP_NOTIFICATIONS_ENABLED),
             /* notifyForDescendants = */ true,
-            observer
+            observer,
         )
 
         // QQQ: Do we need to register for SETTING_HEADS_UP_TICKER? It seems unused.
@@ -139,7 +139,7 @@
 
 class PeekAlreadyBubbledSuppressor(
     private val statusBarStateController: StatusBarStateController,
-    private val bubbles: Optional<Bubbles>
+    private val bubbles: Optional<Bubbles>,
 ) : VisualInterruptionFilter(types = setOf(PEEK), reason = "already bubbled") {
     override fun shouldSuppress(entry: NotificationEntry) =
         when {
@@ -164,7 +164,7 @@
 
 class PeekDeviceNotInUseSuppressor(
     private val powerManager: PowerManager,
-    private val statusBarStateController: StatusBarStateController
+    private val statusBarStateController: StatusBarStateController,
 ) : VisualInterruptionCondition(types = setOf(PEEK), reason = "device not in use") {
     override fun shouldSuppress() =
         when {
@@ -177,7 +177,7 @@
     VisualInterruptionFilter(
         types = setOf(PEEK),
         reason = "has old `when`",
-        uiEventId = HUN_SUPPRESSED_OLD_WHEN
+        uiEventId = HUN_SUPPRESSED_OLD_WHEN,
     ) {
     private fun whenAge(entry: NotificationEntry) =
         systemClock.currentTimeMillis() - entry.sbn.notification.getWhen()
@@ -206,7 +206,7 @@
 class PulseLockscreenVisibilityPrivateSuppressor :
     VisualInterruptionFilter(
         types = setOf(PULSE),
-        reason = "hidden by lockscreen visibility override"
+        reason = "hidden by lockscreen visibility override",
     ) {
     override fun shouldSuppress(entry: NotificationEntry) =
         entry.ranking.lockscreenVisibilityOverride == VISIBILITY_PRIVATE
@@ -220,7 +220,7 @@
 class HunGroupAlertBehaviorSuppressor :
     VisualInterruptionFilter(
         types = setOf(PEEK, PULSE),
-        reason = "suppressive group alert behavior"
+        reason = "suppressive group alert behavior",
     ) {
     override fun shouldSuppress(entry: NotificationEntry) =
         entry.sbn.let { it.isGroup && it.notification.suppressAlertingDueToGrouping() }
@@ -282,11 +282,7 @@
     private val notificationManager: NotificationManager,
     private val logger: VisualInterruptionDecisionLogger,
     private val systemSettings: SystemSettings,
-) :
-    VisualInterruptionFilter(
-        types = setOf(PEEK, PULSE),
-        reason = "avalanche",
-    ) {
+) : VisualInterruptionFilter(types = setOf(PEEK, PULSE), reason = "avalanche") {
     val TAG = "AvalancheSuppressor"
 
     private val prefs = context.getSharedPreferences(context.packageName, Context.MODE_PRIVATE)
@@ -324,7 +320,7 @@
         ALLOW_FSI_WITH_PERMISSION_ON,
         ALLOW_COLORIZED,
         ALLOW_EMERGENCY,
-        SUPPRESS
+        SUPPRESS,
     }
 
     enum class AvalancheEvent(private val id: Int) : UiEventLogger.UiEventEnum {
@@ -354,6 +350,7 @@
         AVALANCHE_SUPPRESSOR_HUN_ALLOWED_CATEGORY_CAR_EMERGENCY(1868),
         @UiEvent(doc = "HUN allowed during avalanche because it is a car warning")
         AVALANCHE_SUPPRESSOR_HUN_ALLOWED_CATEGORY_CAR_WARNING(1869);
+
         override fun getId(): Int {
             return id
         }
@@ -399,7 +396,7 @@
         val bundle = Bundle()
         bundle.putString(
             Notification.EXTRA_SUBSTITUTE_APP_NAME,
-            context.getString(com.android.internal.R.string.android_system_label)
+            context.getString(com.android.internal.R.string.android_system_label),
         )
 
         val builder =
@@ -452,7 +449,8 @@
 
         if (entry.sbn.notification.category == CATEGORY_CAR_EMERGENCY) {
             uiEventLogger.log(
-                    AvalancheEvent.AVALANCHE_SUPPRESSOR_HUN_ALLOWED_CATEGORY_CAR_EMERGENCY)
+                AvalancheEvent.AVALANCHE_SUPPRESSOR_HUN_ALLOWED_CATEGORY_CAR_EMERGENCY
+            )
             return State.ALLOW_CATEGORY_CAR_EMERGENCY
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index 450067a..f586051 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -47,7 +47,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.EventLog;
 import com.android.systemui.util.settings.GlobalSettings;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
index 52336be..b831b94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.shared.notifications.domain.interactor.NotificationSettingsInteractor
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider.Decision
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider.FullScreenIntentDecision
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionSuppressor.EventLogData
@@ -41,7 +42,6 @@
 import com.android.systemui.statusbar.notification.shared.NotificationAvalancheSuppression
 import com.android.systemui.statusbar.policy.BatteryController
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.EventLog
 import com.android.systemui.util.settings.GlobalSettings
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt
new file mode 100644
index 0000000..f400d60
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt
@@ -0,0 +1,157 @@
+/*
+ * 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.statusbar.notification.promoted
+
+import android.app.Notification
+import android.app.Notification.BigPictureStyle
+import android.app.Notification.BigTextStyle
+import android.app.Notification.CallStyle
+import android.app.Notification.EXTRA_CHRONOMETER_COUNT_DOWN
+import android.app.Notification.EXTRA_SUB_TEXT
+import android.app.Notification.EXTRA_TEXT
+import android.app.Notification.EXTRA_TITLE
+import android.app.Notification.ProgressStyle
+import android.content.Context
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Style
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.When
+import javax.inject.Inject
+
+@SysUISingleton
+class PromotedNotificationContentExtractor
+@Inject
+constructor(
+    private val promotedNotificationsProvider: PromotedNotificationsProvider,
+    private val context: Context,
+    private val logger: PromotedNotificationLogger,
+) {
+    fun extractContent(
+        entry: NotificationEntry,
+        recoveredBuilder: Notification.Builder,
+    ): PromotedNotificationContentModel? {
+        if (!PromotedNotificationContentModel.featureFlagEnabled()) {
+            logger.logExtractionSkipped(entry, "feature flags disabled")
+            return null
+        }
+
+        if (!promotedNotificationsProvider.shouldPromote(entry)) {
+            logger.logExtractionSkipped(entry, "shouldPromote returned false")
+            return null
+        }
+
+        val notification = entry.sbn.notification
+        if (notification == null) {
+            logger.logExtractionFailed(entry, "entry.sbn.notification is null")
+            return null
+        }
+
+        val contentBuilder = PromotedNotificationContentModel.Builder(entry.key)
+
+        // TODO: Pitch a fit if style is unsupported or mandatory fields are missing once
+        // FLAG_PROMOTED_ONGOING is set reliably and we're not testing status bar chips.
+
+        contentBuilder.skeletonSmallIcon = entry.icons.aodIcon?.sourceIcon
+        contentBuilder.appName = notification.loadHeaderAppName(context)
+        contentBuilder.subText = notification.subText()
+        contentBuilder.time = notification.extractWhen()
+        contentBuilder.lastAudiblyAlertedMs = entry.lastAudiblyAlertedMs
+        contentBuilder.profileBadgeResId = null // TODO
+        contentBuilder.title = notification.title()
+        contentBuilder.text = notification.text()
+        contentBuilder.skeletonLargeIcon = null // TODO
+
+        recoveredBuilder.style?.extractContent(contentBuilder)
+            ?: run { contentBuilder.style = Style.Ineligible }
+
+        return contentBuilder.build().also { logger.logExtractionSucceeded(entry, it) }
+    }
+}
+
+private fun Notification.title(): CharSequence? = extras?.getCharSequence(EXTRA_TITLE)
+
+private fun Notification.text(): CharSequence? = extras?.getCharSequence(EXTRA_TEXT)
+
+private fun Notification.subText(): String? = extras?.getString(EXTRA_SUB_TEXT)
+
+private fun Notification.chronometerCountDown(): Boolean =
+    extras?.getBoolean(EXTRA_CHRONOMETER_COUNT_DOWN, /* defaultValue= */ false) ?: false
+
+private fun Notification.extractWhen(): When? {
+    val time = `when`
+    val showsTime = showsTime()
+    val showsChronometer = showsChronometer()
+    val countDown = chronometerCountDown()
+
+    return when {
+        showsTime -> When(time, When.Mode.Absolute)
+        showsChronometer -> When(time, if (countDown) When.Mode.CountDown else When.Mode.CountUp)
+        else -> null
+    }
+}
+
+private fun Notification.Style.extractContent(
+    contentBuilder: PromotedNotificationContentModel.Builder
+) {
+    contentBuilder.style =
+        when (this) {
+            is BigPictureStyle -> {
+                extractContent(contentBuilder)
+                Style.BigPicture
+            }
+
+            is BigTextStyle -> {
+                extractContent(contentBuilder)
+                Style.BigText
+            }
+
+            is CallStyle -> {
+                extractContent(contentBuilder)
+                Style.Call
+            }
+
+            is ProgressStyle -> {
+                extractContent(contentBuilder)
+                Style.Progress
+            }
+
+            else -> Style.Ineligible
+        }
+}
+
+private fun BigPictureStyle.extractContent(
+    contentBuilder: PromotedNotificationContentModel.Builder
+) {
+    // TODO?
+}
+
+private fun BigTextStyle.extractContent(contentBuilder: PromotedNotificationContentModel.Builder) {
+    // TODO?
+}
+
+private fun CallStyle.extractContent(contentBuilder: PromotedNotificationContentModel.Builder) {
+    contentBuilder.personIcon = null // TODO
+    contentBuilder.personName = null // TODO
+    contentBuilder.verificationIcon = null // TODO
+    contentBuilder.verificationText = null // TODO
+}
+
+private fun ProgressStyle.extractContent(contentBuilder: PromotedNotificationContentModel.Builder) {
+    // TODO: Create NotificationProgressModel.toSkeleton, or something similar.
+    contentBuilder.progress = createProgressModel(0xffffffff.toInt(), 0x00000000)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLogger.kt
new file mode 100644
index 0000000..13ad141
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLogger.kt
@@ -0,0 +1,71 @@
+/*
+ * 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.statusbar.notification.promoted
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.LogLevel.ERROR
+import com.android.systemui.log.core.LogLevel.INFO
+import com.android.systemui.log.dagger.NotificationLog
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.logKey
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
+import javax.inject.Inject
+
+class PromotedNotificationLogger
+@Inject
+constructor(@NotificationLog private val buffer: LogBuffer) {
+    fun logExtractionSkipped(entry: NotificationEntry, reason: String) {
+        buffer.log(
+            EXTRACTION_TAG,
+            INFO,
+            {
+                str1 = entry.logKey
+                str2 = reason
+            },
+            { "extraction skipped: $str2 for $str1" },
+        )
+    }
+
+    fun logExtractionFailed(entry: NotificationEntry, reason: String) {
+        buffer.log(
+            EXTRACTION_TAG,
+            ERROR,
+            {
+                str1 = entry.logKey
+                str2 = reason
+            },
+            { "extraction failed: $str2 for $str1" },
+        )
+    }
+
+    fun logExtractionSucceeded(
+        entry: NotificationEntry,
+        content: PromotedNotificationContentModel,
+    ) {
+        buffer.log(
+            EXTRACTION_TAG,
+            INFO,
+            {
+                str1 = entry.logKey
+                str2 = content.toString()
+            },
+            { "extraction succeeded: $str2 for $str1" },
+        )
+    }
+}
+
+private const val EXTRACTION_TAG = "PromotedNotificationContentExtractor"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationsProvider.kt
index 691dc6f..947d9e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationsProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationsProvider.kt
@@ -19,6 +19,7 @@
 import android.app.Notification.FLAG_PROMOTED_ONGOING
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
 import javax.inject.Inject
 
 /** A provider for making decisions on which notifications should be promoted. */
@@ -30,7 +31,7 @@
 @SysUISingleton
 open class PromotedNotificationsProviderImpl @Inject constructor() : PromotedNotificationsProvider {
     override fun shouldPromote(entry: NotificationEntry): Boolean {
-        if (!PromotedNotificationUi.isEnabled) {
+        if (!PromotedNotificationContentModel.featureFlagEnabled()) {
             return false
         }
         return (entry.sbn.notification.flags and FLAG_PROMOTED_ONGOING) != 0
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index a90a105..7ad65fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.row;
 
+import static android.app.Flags.notificationsRedesignTemplates;
 import static android.app.Notification.Action.SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY;
 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
 
@@ -36,6 +37,7 @@
 import android.graphics.Canvas;
 import android.graphics.Path;
 import android.graphics.Point;
+import android.graphics.Rect;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.Drawable;
@@ -101,6 +103,8 @@
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.PinnedStatus;
 import com.android.systemui.statusbar.notification.logging.NotificationCounters;
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
@@ -108,6 +112,7 @@
 import com.android.systemui.statusbar.notification.row.shared.LockscreenOtpRedaction;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationCompactMessagingTemplateViewWrapper;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
+import com.android.systemui.statusbar.notification.shared.NotificationAddXOnHoverToDismiss;
 import com.android.systemui.statusbar.notification.shared.NotificationContentAlphaOptimization;
 import com.android.systemui.statusbar.notification.shared.TransparentHeaderFix;
 import com.android.systemui.statusbar.notification.stack.AmbientState;
@@ -118,13 +123,13 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.SwipeableView;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
 import com.android.systemui.statusbar.policy.RemoteInputView;
 import com.android.systemui.statusbar.policy.SmartReplyConstants;
 import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
 import com.android.systemui.util.Compile;
 import com.android.systemui.util.DumpUtilsKt;
+import com.android.systemui.util.ListenerSet;
 import com.android.systemui.wmshell.BubblesManager;
 
 import java.io.PrintWriter;
@@ -277,7 +282,7 @@
     private NotificationMenuRowPlugin mMenuRow;
     private ViewStub mGutsStub;
     private boolean mIsSystemChildExpanded;
-    private boolean mIsPinned;
+    private PinnedStatus mPinnedStatus = PinnedStatus.NotPinned;
     private boolean mExpandAnimationRunning;
     private AboveShelfChangedListener mAboveShelfChangedListener;
     private HeadsUpManager mHeadsUpManager;
@@ -430,6 +435,10 @@
     private float mBottomRoundnessDuringLaunchAnimation;
     private float mSmallRoundness;
 
+    private ListenerSet<DismissButtonTargetVisibilityListener>
+            mDismissButtonTargetVisibilityListeners
+            = new ListenerSet();
+
     public NotificationContentView[] getLayouts() {
         return Arrays.copyOf(mLayouts, mLayouts.length);
     }
@@ -739,6 +748,73 @@
         }
     }
 
+    public interface DismissButtonTargetVisibilityListener {
+        // Called when the notification dismiss button's target visibility changes.
+        // NOTE: This can be called when the dismiss button already has the target visibility.
+        void onTargetVisibilityChanged(boolean targetVisible);
+    }
+
+    public void addDismissButtonTargetStateListener(
+            DismissButtonTargetVisibilityListener listener) {
+        if (NotificationAddXOnHoverToDismiss.isUnexpectedlyInLegacyMode()) {
+            return;
+        }
+
+        mDismissButtonTargetVisibilityListeners.addIfAbsent(listener);
+    }
+
+    public void removeDismissButtonTargetStateListener(
+            DismissButtonTargetVisibilityListener listener) {
+        if (NotificationAddXOnHoverToDismiss.isUnexpectedlyInLegacyMode()) {
+            return;
+        }
+
+        mDismissButtonTargetVisibilityListeners.remove(listener);
+    }
+
+    @Override
+    public boolean onInterceptHoverEvent(MotionEvent event) {
+        if (!NotificationAddXOnHoverToDismiss.isEnabled()) {
+            return super.onInterceptHoverEvent(event);
+        }
+
+        // Do not bother checking the dismiss button's target visibility if the notification cannot
+        // be dismissed.
+        if (!canEntryBeDismissed()) {
+            return false;
+        }
+
+        final Boolean targetVisible = getDismissButtonTargetVisibilityIfAny(event);
+        if (targetVisible != null) {
+            for (DismissButtonTargetVisibilityListener listener :
+                    mDismissButtonTargetVisibilityListeners) {
+                listener.onTargetVisibilityChanged(targetVisible.booleanValue());
+            }
+        }
+
+        // Do not consume the hover event so that children still have a chance to process it.
+        return false;
+    }
+
+    private @Nullable Boolean getDismissButtonTargetVisibilityIfAny(MotionEvent event) {
+        // Returns the dismiss button's target visibility resulted by `event`. Returns null if the
+        // target visibility should not change.
+
+        if (event.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
+            // The notification dismiss button should be hidden when the hover exit event is located
+            // outside of the notification. NOTE: The hover exit event can be inside the
+            // notification if hover moves from one hoverable child to another.
+            final Rect localBounds = new Rect(0, 0, this.getWidth(), this.getActualHeight());
+            if (!localBounds.contains((int) event.getX(), (int) event.getY())) {
+                return Boolean.FALSE;
+            }
+        } else if (event.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
+            return Boolean.TRUE;
+        }
+
+        return null;
+    }
+
     private void updateLimitsForView(NotificationContentView layout) {
         View contractedView = layout.getContractedChild();
         boolean customView = contractedView != null
@@ -1154,17 +1230,15 @@
     /**
      * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
      * the notification will be rendered on top of the screen.
-     *
-     * @param pinned whether it is pinned
      */
-    public void setPinned(boolean pinned) {
+    public void setPinnedStatus(PinnedStatus pinnedStatus) {
         int intrinsicHeight = getIntrinsicHeight();
         boolean wasAboveShelf = isAboveShelf();
-        mIsPinned = pinned;
+        mPinnedStatus = pinnedStatus;
         if (intrinsicHeight != getIntrinsicHeight()) {
             notifyHeightChanged(/* needsAnimation= */ false);
         }
-        if (pinned) {
+        if (pinnedStatus.isPinned()) {
             setAnimationRunning(true);
             mExpandedWhenPinned = false;
         } else if (mExpandedWhenPinned) {
@@ -1178,7 +1252,7 @@
 
     @Override
     public boolean isPinned() {
-        return mIsPinned;
+        return mPinnedStatus.isPinned();
     }
 
     @Override
@@ -1536,6 +1610,10 @@
         return mPrivateLayout.getSingleLineView();
     }
 
+    /**
+     * Whether this row is displayed over the unoccluded lockscreen. Returns false on the
+     * locked shade.
+     */
     public boolean isOnKeyguard() {
         return mOnKeyguard;
     }
@@ -2006,8 +2084,13 @@
                 R.dimen.notification_min_height_before_p);
         mMaxSmallHeightBeforeS = NotificationUtils.getFontScaledHeight(mContext,
                 R.dimen.notification_min_height_before_s);
-        mMaxSmallHeight = NotificationUtils.getFontScaledHeight(mContext,
-                R.dimen.notification_min_height);
+        if (notificationsRedesignTemplates()) {
+            mMaxSmallHeight = NotificationUtils.getFontScaledHeight(mContext,
+                    R.dimen.notification_2025_min_height);
+        } else {
+            mMaxSmallHeight = NotificationUtils.getFontScaledHeight(mContext,
+                    R.dimen.notification_min_height);
+        }
         mMaxSmallHeightLarge = NotificationUtils.getFontScaledHeight(mContext,
                 R.dimen.notification_min_height_increased);
         mMaxExpandedHeight = NotificationUtils.getFontScaledHeight(mContext,
@@ -2214,6 +2297,10 @@
         mTranslateableViews.remove(mGutsStub);
         // We don't handle focus highlight in this view, it's done in background drawable instead
         setDefaultFocusHighlightEnabled(false);
+
+        if (NotificationAddXOnHoverToDismiss.isEnabled()) {
+            addDismissButtonTargetStateListener(findViewById(R.id.backgroundNormal));
+        }
     }
 
     /**
@@ -2820,7 +2907,8 @@
         }
     }
 
-    void setOnKeyguard(boolean onKeyguard) {
+    /** @see #isOnKeyguard() */
+    public void setOnKeyguard(boolean onKeyguard) {
         if (onKeyguard != mOnKeyguard) {
             boolean wasAboveShelf = isAboveShelf();
             final boolean wasExpanded = isExpanded();
@@ -3749,7 +3837,8 @@
     @Override
     public boolean isAboveShelf() {
         return (canShowHeadsUp()
-                && (mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf)
+                && (mPinnedStatus.isPinned()
+                || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf)
                 || mExpandAnimationRunning || mChildIsExpanding));
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index baad616..a150f7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -41,6 +41,7 @@
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
 import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.FeedbackIcon;
@@ -58,7 +59,7 @@
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.notification.stack.ui.view.NotificationRowStatsLogger;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.policy.SmartReplyConstants;
 import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
 import com.android.systemui.util.time.SystemClock;
@@ -378,15 +379,19 @@
                 mView.getEntry().setInitializationTime(mClock.elapsedRealtime());
                 mPluginManager.addPluginListener(mView,
                         NotificationMenuRowPlugin.class, false /* Allow multiple */);
-                mView.setOnKeyguard(mStatusBarStateController.getState() == KEYGUARD);
-                mStatusBarStateController.addCallback(mStatusBarStateListener);
+                if (!SceneContainerFlag.isEnabled()) {
+                    mView.setOnKeyguard(mStatusBarStateController.getState() == KEYGUARD);
+                    mStatusBarStateController.addCallback(mStatusBarStateListener);
+                }
                 mSettingsController.addCallback(BUBBLES_SETTING_URI, mSettingsListener);
             }
 
             @Override
             public void onViewDetachedFromWindow(View v) {
                 mPluginManager.removePluginListener(mView);
-                mStatusBarStateController.removeCallback(mStatusBarStateListener);
+                if (!SceneContainerFlag.isEnabled()) {
+                    mStatusBarStateController.removeCallback(mStatusBarStateListener);
+                }
                 mSettingsController.removeCallback(BUBBLES_SETTING_URI, mSettingsListener);
             }
         });
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
index 77f5717..11db2fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
@@ -52,7 +52,7 @@
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 
 import javax.inject.Inject;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
index d0db514..34ef639 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
@@ -21,7 +21,9 @@
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.Canvas;
+import android.graphics.Path;
 import android.graphics.PorterDuff;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.LayerDrawable;
@@ -36,6 +38,7 @@
 import com.android.settingslib.Utils;
 import com.android.systemui.Dumpable;
 import com.android.systemui.res.R;
+import com.android.systemui.statusbar.notification.shared.NotificationAddXOnHoverToDismiss;
 import com.android.systemui.util.DrawableDumpKt;
 
 import java.io.PrintWriter;
@@ -44,7 +47,8 @@
 /**
  * A view that can be used for both the dimmed and normal background of an notification.
  */
-public class NotificationBackgroundView extends View implements Dumpable {
+public class NotificationBackgroundView extends View implements Dumpable,
+        ExpandableNotificationRow.DismissButtonTargetVisibilityListener {
 
     private final boolean mDontModifyCorners;
     private Drawable mBackground;
@@ -66,6 +70,11 @@
     private final ColorStateList mLightColoredStatefulColors;
     private final ColorStateList mDarkColoredStatefulColors;
     private final int mNormalColor;
+    private final int convexR = 9;
+    private final int concaveR = 22;
+
+    // True only if the dismiss button is visible.
+    private boolean mDrawDismissButtonCutout = false;
 
     public NotificationBackgroundView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -80,6 +89,18 @@
     }
 
     @Override
+    public void onTargetVisibilityChanged(boolean targetVisible) {
+        if (NotificationAddXOnHoverToDismiss.isUnexpectedlyInLegacyMode()) {
+            return;
+        }
+
+        if (mDrawDismissButtonCutout != targetVisible) {
+            mDrawDismissButtonCutout = targetVisible;
+            invalidate();
+        }
+    }
+
+    @Override
     protected void onDraw(Canvas canvas) {
         if (mClipTopAmount + mClipBottomAmount < getActualHeight() || mExpandAnimationRunning) {
             canvas.save();
@@ -87,12 +108,87 @@
                 canvas.clipRect(0, mClipTopAmount, getWidth(),
                         getActualHeight() - mClipBottomAmount);
             }
-            draw(canvas, mBackground);
+
+            if (!NotificationAddXOnHoverToDismiss.isEnabled()) {
+                draw(canvas, mBackground);
+                canvas.restore();
+                return;
+            }
+
+            Rect backgroundBounds = null;
+            if (mBackground != null || mDrawDismissButtonCutout) {
+                backgroundBounds = calculateBackgroundBounds();
+            }
+
+            if (mDrawDismissButtonCutout) {
+                canvas.clipPath(calculateDismissButtonCutoutPath(backgroundBounds));
+            }
+
+            if (mBackground != null) {
+                mBackground.setBounds(backgroundBounds);
+                mBackground.draw(canvas);
+            }
+
             canvas.restore();
         }
     }
 
+    private Path calculateDismissButtonCutoutPath(Rect backgroundBounds) {
+        // TODO(b/365585705): Adapt to RTL after the UX design is finalized.
+
+        NotificationAddXOnHoverToDismiss.isUnexpectedlyInLegacyMode();
+
+        Path path = new Path();
+
+        final int left = backgroundBounds.left;
+        final int right = backgroundBounds.right;
+        final int top = backgroundBounds.top;
+        final int bottom = backgroundBounds.bottom;
+
+        // Generate the path clockwise from the left-top corner.
+        path.moveTo(left, top);
+        path.lineTo(right - 2 * convexR - concaveR, top);
+        path.quadTo(right - convexR - concaveR, top, right - convexR - concaveR,
+                top + convexR);
+        path.quadTo(right - convexR - concaveR, top + convexR + concaveR, right - convexR,
+                top + convexR + concaveR);
+        path.quadTo(right, top + convexR + concaveR, right, top + 2 * convexR + concaveR);
+        path.lineTo(right, bottom);
+        path.lineTo(left, bottom);
+        path.lineTo(left, top);
+
+        return path;
+    }
+
+    private Rect calculateBackgroundBounds() {
+        NotificationAddXOnHoverToDismiss.isUnexpectedlyInLegacyMode();
+
+        int top = 0;
+        int bottom = getActualHeight();
+        if (mBottomIsRounded
+                && mBottomAmountClips
+                && !mExpandAnimationRunning) {
+            bottom -= mClipBottomAmount;
+        }
+        final boolean isRtl = isLayoutRtl();
+        final int width = getWidth();
+        final int actualWidth = getActualWidth();
+
+        int left = isRtl ? width - actualWidth : 0;
+        int right = isRtl ? width : actualWidth;
+
+        if (mExpandAnimationRunning) {
+            // Horizontally center this background view inside of the container
+            left = (int) ((width - actualWidth) / 2.0f);
+            right = (int) (left + actualWidth);
+        }
+
+        return new Rect(left, top, right, bottom);
+    }
+
     private void draw(Canvas canvas, Drawable drawable) {
+        NotificationAddXOnHoverToDismiss.assertInLegacyMode();
+
         if (drawable != null) {
             int top = 0;
             int bottom = getActualHeight();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 41abac1..6e05e8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -54,6 +54,8 @@
 import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
 import com.android.systemui.statusbar.notification.InflationException;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor;
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel;
 import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation;
 import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation;
 import com.android.systemui.statusbar.notification.row.shared.LockscreenOtpRedaction;
@@ -92,6 +94,7 @@
     private final SmartReplyStateInflater mSmartReplyStateInflater;
     private final NotifLayoutInflaterFactory.Provider mNotifLayoutInflaterFactoryProvider;
     private final HeadsUpStyleProvider mHeadsUpStyleProvider;
+    private final PromotedNotificationContentExtractor mPromotedNotificationContentExtractor;
 
     private final NotificationRowContentBinderLogger mLogger;
 
@@ -105,6 +108,7 @@
             SmartReplyStateInflater smartRepliesInflater,
             NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider,
             HeadsUpStyleProvider headsUpStyleProvider,
+            PromotedNotificationContentExtractor promotedNotificationContentExtractor,
             NotificationRowContentBinderLogger logger) {
         NotificationRowContentBinderRefactor.assertInLegacyMode();
         mRemoteViewCache = remoteViewCache;
@@ -115,6 +119,7 @@
         mSmartReplyStateInflater = smartRepliesInflater;
         mNotifLayoutInflaterFactoryProvider = notifLayoutInflaterFactoryProvider;
         mHeadsUpStyleProvider = headsUpStyleProvider;
+        mPromotedNotificationContentExtractor = promotedNotificationContentExtractor;
         mLogger = logger;
     }
 
@@ -165,6 +170,7 @@
                 mSmartReplyStateInflater,
                 mNotifLayoutInflaterFactoryProvider,
                 mHeadsUpStyleProvider,
+                mPromotedNotificationContentExtractor,
                 mLogger);
         if (mInflateSynchronously) {
             task.onPostExecute(task.doInBackground());
@@ -913,6 +919,11 @@
         NotificationContentView privateLayout = row.getPrivateLayout();
         NotificationContentView publicLayout = row.getPublicLayout();
         logger.logAsyncTaskProgress(entry, "finishing");
+
+        if (PromotedNotificationContentModel.featureFlagEnabled()) {
+            entry.setPromotedNotificationContentModel(result.mExtractedPromotedNotificationContent);
+        }
+
         boolean setRepliesAndActions = true;
         if ((reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0) {
             if (result.inflatedContentView != null) {
@@ -1123,6 +1134,7 @@
         private final SmartReplyStateInflater mSmartRepliesInflater;
         private final NotifLayoutInflaterFactory.Provider mNotifLayoutInflaterFactoryProvider;
         private final HeadsUpStyleProvider mHeadsUpStyleProvider;
+        private final PromotedNotificationContentExtractor mPromotedNotificationContentExtractor;
         private final NotificationRowContentBinderLogger mLogger;
 
         private AsyncInflationTask(
@@ -1142,6 +1154,7 @@
                 SmartReplyStateInflater smartRepliesInflater,
                 NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider,
                 HeadsUpStyleProvider headsUpStyleProvider,
+                PromotedNotificationContentExtractor promotedNotificationContentExtractor,
                 NotificationRowContentBinderLogger logger) {
             mEntry = entry;
             mRow = row;
@@ -1160,6 +1173,7 @@
             mIsMediaInQS = isMediaFlagEnabled;
             mNotifLayoutInflaterFactoryProvider = notifLayoutInflaterFactoryProvider;
             mHeadsUpStyleProvider = headsUpStyleProvider;
+            mPromotedNotificationContentExtractor = promotedNotificationContentExtractor;
             mLogger = logger;
             entry.setInflationTask(this);
         }
@@ -1276,6 +1290,14 @@
                         );
             }
 
+            if (PromotedNotificationContentModel.featureFlagEnabled()) {
+                mLogger.logAsyncTaskProgress(mEntry, "extracting promoted notification content");
+                result.mExtractedPromotedNotificationContent = mPromotedNotificationContentExtractor
+                        .extractContent(mEntry, recoveredBuilder);
+                mLogger.logAsyncTaskProgress(mEntry, "extracted promoted notification content: "
+                        + result.mExtractedPromotedNotificationContent);
+            }
+
             mLogger.logAsyncTaskProgress(mEntry,
                     "getting row image resolver (on wrong thread!)");
             final NotificationInlineImageResolver imageResolver = mRow.getImageResolver();
@@ -1377,6 +1399,8 @@
 
     @VisibleForTesting
     static class InflationProgress {
+        PromotedNotificationContentModel mExtractedPromotedNotificationContent;
+
         private RemoteViews newContentView;
         private RemoteViews newHeadsUpView;
         private RemoteViews newExpandedView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 5ff9bc6..ea50874 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -72,7 +72,7 @@
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.wmshell.BubblesManager;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
index d0c033b..c7d80e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
@@ -16,6 +16,7 @@
 package com.android.systemui.statusbar.notification.row
 
 import android.annotation.SuppressLint
+import android.app.Flags
 import android.app.Notification
 import android.content.Context
 import android.content.ContextWrapper
@@ -46,6 +47,8 @@
 import com.android.systemui.statusbar.notification.ConversationNotificationProcessor
 import com.android.systemui.statusbar.notification.InflationException
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
 import com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED
 import com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_EXPANDED
 import com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP
@@ -95,6 +98,7 @@
     private val smartReplyStateInflater: SmartReplyStateInflater,
     private val notifLayoutInflaterFactoryProvider: NotifLayoutInflaterFactory.Provider,
     private val headsUpStyleProvider: HeadsUpStyleProvider,
+    private val promotedNotificationContentExtractor: PromotedNotificationContentExtractor,
     private val logger: NotificationRowContentBinderLogger,
 ) : NotificationRowContentBinder {
 
@@ -147,6 +151,7 @@
                 /* isMediaFlagEnabled = */ smartReplyStateInflater,
                 notifLayoutInflaterFactoryProvider,
                 headsUpStyleProvider,
+                promotedNotificationContentExtractor,
                 logger,
             )
         if (inflateSynchronously) {
@@ -166,6 +171,7 @@
         builder: Notification.Builder,
         packageContext: Context,
         smartRepliesInflater: SmartReplyStateInflater,
+        promotedNotificationContentExtractor: PromotedNotificationContentExtractor,
     ): InflationProgress {
         val systemUIContext = row.context
         val result =
@@ -182,6 +188,7 @@
                 notifLayoutInflaterFactoryProvider = notifLayoutInflaterFactoryProvider,
                 headsUpStyleProvider = headsUpStyleProvider,
                 conversationProcessor = conversationProcessor,
+                promotedNotificationContentExtractor = promotedNotificationContentExtractor,
                 logger = logger,
             )
         inflateSmartReplyViews(
@@ -372,6 +379,7 @@
         private val smartRepliesInflater: SmartReplyStateInflater,
         private val notifLayoutInflaterFactoryProvider: NotifLayoutInflaterFactory.Provider,
         private val headsUpStyleProvider: HeadsUpStyleProvider,
+        private val promotedNotificationContentExtractor: PromotedNotificationContentExtractor,
         private val logger: NotificationRowContentBinderLogger,
     ) : AsyncTask<Void, Void, Result<InflationProgress>>(), InflationCallback, InflationTask {
         private val context: Context
@@ -442,6 +450,7 @@
                     notifLayoutInflaterFactoryProvider = notifLayoutInflaterFactoryProvider,
                     headsUpStyleProvider = headsUpStyleProvider,
                     conversationProcessor = conversationProcessor,
+                    promotedNotificationContentExtractor = promotedNotificationContentExtractor,
                     logger = logger,
                 )
             logger.logAsyncTaskProgress(
@@ -582,6 +591,7 @@
         @VisibleForTesting val packageContext: Context,
         val remoteViews: NewRemoteViews,
         val contentModel: NotificationContentModel,
+        val extractedPromotedNotificationContentModel: PromotedNotificationContentModel?,
     ) {
 
         var inflatedContentView: View? = null
@@ -670,8 +680,23 @@
             notifLayoutInflaterFactoryProvider: NotifLayoutInflaterFactory.Provider,
             headsUpStyleProvider: HeadsUpStyleProvider,
             conversationProcessor: ConversationNotificationProcessor,
+            promotedNotificationContentExtractor: PromotedNotificationContentExtractor,
             logger: NotificationRowContentBinderLogger,
         ): InflationProgress {
+            val promoted =
+                if (PromotedNotificationContentModel.featureFlagEnabled()) {
+                    logger.logAsyncTaskProgress(entry, "extracting promoted notification content")
+                    val extracted =
+                        promotedNotificationContentExtractor.extractContent(entry, builder)
+                    logger.logAsyncTaskProgress(
+                        entry,
+                        "extracted promoted notification content: {extracted}",
+                    )
+                    extracted
+                } else {
+                    null
+                }
+
             // process conversations and extract the messaging style
             val messagingStyle =
                 if (entry.ranking.isConversation) {
@@ -734,6 +759,7 @@
                 packageContext = packageContext,
                 remoteViews = remoteViews,
                 contentModel = contentModel,
+                extractedPromotedNotificationContentModel = promoted,
             )
         }
 
@@ -1393,6 +1419,11 @@
             logger.logAsyncTaskProgress(entry, "finishing")
 
             entry.setContentModel(result.contentModel)
+            if (PromotedNotificationContentModel.featureFlagEnabled()) {
+                entry.promotedNotificationContentModel =
+                    result.extractedPromotedNotificationContentModel
+            }
+
             result.inflatedSmartReplyState?.let { row.privateLayout.setInflatedSmartReplyState(it) }
 
             setContentViewsFromRemoteViews(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index b622def..e9eecdd8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.statusbar.notification.row.wrapper;
 
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+
 import static com.android.systemui.statusbar.notification.TransformState.TRANSFORM_Y;
 
 import android.app.Notification;
@@ -48,6 +51,7 @@
 import com.android.systemui.statusbar.notification.RoundableState;
 import com.android.systemui.statusbar.notification.TransformState;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.shared.NotificationAddXOnHoverToDismiss;
 
 import java.util.Stack;
 
@@ -115,6 +119,10 @@
         resolveHeaderViews();
         addFeedbackOnClickListener(row);
         addCloseButtonOnClickListener(row);
+
+        if (NotificationAddXOnHoverToDismiss.isEnabled()) {
+            mRow.addDismissButtonTargetStateListener(mHoverListener);
+        }
     }
 
     @Override
@@ -166,13 +174,34 @@
         }
     }
 
+    private ExpandableNotificationRow.DismissButtonTargetVisibilityListener mHoverListener = new
+            ExpandableNotificationRow.DismissButtonTargetVisibilityListener() {
+                @Override
+                public void onTargetVisibilityChanged(boolean targetVisible) {
+                    NotificationAddXOnHoverToDismiss.isUnexpectedlyInLegacyMode();
+
+                    if (mCloseButton != null) {
+                        mCloseButton.setVisibility(targetVisible ? VISIBLE : GONE);
+                    }
+                }
+            };
+
+    @Override
+    public void setRemoved() {
+        super.setRemoved();
+
+        if (NotificationAddXOnHoverToDismiss.isEnabled()) {
+            mRow.removeDismissButtonTargetStateListener(mHoverListener);
+        }
+    }
+
     /**
      * Shows the given feedback icon, or hides the icon if null.
      */
     @Override
     public void setFeedbackIcon(@Nullable FeedbackIcon icon) {
         if (mFeedbackIcon != null) {
-            mFeedbackIcon.setVisibility(icon != null ? View.VISIBLE : View.GONE);
+            mFeedbackIcon.setVisibility(icon != null ? VISIBLE : GONE);
             if (icon != null) {
                 if (mFeedbackIcon instanceof ImageButton) {
                     ((ImageButton) mFeedbackIcon).setImageResource(icon.getIconRes());
@@ -266,7 +295,7 @@
             boolean expandable,
             View.OnClickListener onClickListener,
             boolean requestLayout) {
-        mExpandButton.setVisibility(expandable ? View.VISIBLE : View.GONE);
+        mExpandButton.setVisibility(expandable ? VISIBLE : GONE);
         mExpandButton.setOnClickListener(expandable ? onClickListener : null);
         if (mAltExpandTarget != null) {
             mAltExpandTarget.setOnClickListener(expandable ? onClickListener : null);
@@ -294,7 +323,7 @@
     @Override
     public void setRecentlyAudiblyAlerted(boolean audiblyAlerted) {
         if (mAudiblyAlertedIcon != null) {
-            mAudiblyAlertedIcon.setVisibility(audiblyAlerted ? View.VISIBLE : View.GONE);
+            mAudiblyAlertedIcon.setVisibility(audiblyAlerted ? VISIBLE : GONE);
         }
     }
 
@@ -371,6 +400,7 @@
             ((DateTimeView) timeView).setTime(whenMillis);
         }
     }
+
     protected void addTransformedViews(View... views) {
         for (View view : views) {
             if (view != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationAddXOnHoverToDismiss.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationAddXOnHoverToDismiss.kt
new file mode 100644
index 0000000..0961874
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationAddXOnHoverToDismiss.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.statusbar.notification.shared
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the notification dismiss button on hover flag state. */
+@Suppress("NOTHING_TO_INLINE")
+object NotificationAddXOnHoverToDismiss {
+    const val FLAG_NAME = Flags.FLAG_NOTIFICATION_ADD_X_ON_HOVER_TO_DISMISS
+
+    val token: FlagToken
+        get() = FlagToken(FLAG_NAME, isEnabled)
+
+    @JvmStatic
+    inline val isEnabled
+        get() = Flags.notificationAddXOnHoverToDismiss()
+
+    @JvmStatic
+    inline fun isUnexpectedlyInLegacyMode() =
+        RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+    @JvmStatic
+    inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 7771421..ad36117 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -39,7 +39,7 @@
 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.BypassController;
 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.policy.AvalancheController;
+import com.android.systemui.statusbar.notification.headsup.AvalancheController;
 
 import java.io.PrintWriter;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
index 5c9a0b9..f85545e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
@@ -100,6 +100,9 @@
      */
     void addContainerViewAt(View v, int index);
 
+    /** Sets whether the notificatios are displayed on the unoccluded lockscreen. */
+    void setOnLockscreen(boolean isOnKeyguard);
+
     /**
      * Sets the maximum number of notifications to display.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index 31e4d2c..043d64e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -21,7 +21,6 @@
 import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.media.controls.ui.controller.KeyguardMediaController
 import com.android.systemui.shade.ShadeDisplayAware
-import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
 import com.android.systemui.statusbar.notification.SourceType
 import com.android.systemui.statusbar.notification.collection.NotificationClassificationFlag
 import com.android.systemui.statusbar.notification.collection.render.MediaContainerController
@@ -36,6 +35,7 @@
 import com.android.systemui.statusbar.notification.dagger.SocialHeader
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.statusbar.notification.stack.PriorityBucket
 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.foldToSparseArray
@@ -51,7 +51,6 @@
 internal constructor(
     @ShadeDisplayAware private val configurationController: ConfigurationController,
     private val keyguardMediaController: KeyguardMediaController,
-    private val sectionsFeatureManager: NotificationSectionsFeatureManager,
     private val mediaContainerController: MediaContainerController,
     private val notificationRoundnessManager: NotificationRoundnessManager,
     @IncomingHeader private val incomingHeaderController: SectionHeaderController,
@@ -120,8 +119,8 @@
     }
 
     fun createSectionsForBuckets(): Array<NotificationSection> =
-        sectionsFeatureManager
-            .getNotificationBuckets()
+        PriorityBucket
+            .getAllInOrder()
             .map { NotificationSection(it) }
             .toTypedArray()
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 57af8ea..223475e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -99,7 +99,7 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.FakeShadowView;
-import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
 import com.android.systemui.statusbar.notification.NotificationTransitionAnimatorController;
 import com.android.systemui.statusbar.notification.NotificationUtils;
@@ -127,7 +127,7 @@
 import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
-import com.android.systemui.statusbar.policy.HeadsUpUtil;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpUtil;
 import com.android.systemui.statusbar.policy.ScrollAdapter;
 import com.android.systemui.statusbar.policy.SplitShadeStateController;
 import com.android.systemui.util.Assert;
@@ -575,6 +575,7 @@
     @Nullable private SplitShadeStateController mSplitShadeStateController = null;
     private boolean mIsSmallLandscapeLockscreenEnabled = false;
     private boolean mSuppressHeightUpdates;
+    private boolean mIsOnLockscreen;
 
     /** Pass splitShadeStateController to view and update split shade */
     public void passSplitShadeStateController(SplitShadeStateController splitShadeStateController) {
@@ -3228,9 +3229,12 @@
     private void onViewAddedInternal(ExpandableView child) {
         updateHideSensitiveForChild(child);
         child.setOnHeightChangedListener(mOnChildHeightChangedListener);
-        if (child instanceof ExpandableNotificationRow) {
+        if (child instanceof ExpandableNotificationRow row) {
             NotificationEntry entry = ((ExpandableNotificationRow) child).getEntry();
             entry.addOnSensitivityChangedListener(mOnChildSensitivityChangedListener);
+            if (SceneContainerFlag.isEnabled()) {
+                row.setOnKeyguard(mIsOnLockscreen);
+            }
         }
         generateAddAnimation(child, false /* fromMoreCard */);
         updateAnimationState(child);
@@ -4752,8 +4756,11 @@
         }
     }
 
-    void goToFullShade(long delay) {
-        SceneContainerFlag.assertInLegacyMode();
+    /**
+     * Requests an animation for the next stack height update, to animate from the constrained stack
+     * displayed on the lock screen, to the scrollable stack displayed in the expanded shade.
+     */
+    public void animateGoToFullShade(long delay) {
         mGoToFullShadeNeedsAnimation = true;
         mGoToFullShadeDelay = delay;
         mNeedsAnimation = true;
@@ -5356,12 +5363,38 @@
         shelf.bind(mAmbientState, this, mController.getNotificationRoundnessManager());
     }
 
+    /**
+     * Whether the notifications are displayed over the unoccluded lockscreen. Returns false on the
+     * locked shade.
+     */
+    public boolean isOnLockscreen() {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return false;
+        return mIsOnLockscreen;
+    }
+
+    /** @see #isOnLockscreen() */
+    public void setOnLockscreen(boolean isOnLockscreen) {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
+        if (mIsOnLockscreen != isOnLockscreen) {
+            mIsOnLockscreen = isOnLockscreen;
+            for (int i = 0; i < getChildCount(); i++) {
+                View child = getChildAt(i);
+                if (child instanceof ExpandableNotificationRow childRow) {
+                    childRow.setOnKeyguard(isOnLockscreen);
+                }
+            }
+        }
+    }
+
     public void setMaxDisplayedNotifications(int maxDisplayedNotifications) {
         if (mMaxDisplayedNotifications != maxDisplayedNotifications) {
             mMaxDisplayedNotifications = maxDisplayedNotifications;
             if (SceneContainerFlag.isEnabled()) {
                 updateIntrinsicStackHeight();
                 updateStackEndHeightAndStackHeight(mAmbientState.getExpansionFraction());
+                if (maxDisplayedNotifications == -1) {
+                    animateGoToFullShade(0);
+                }
             } else {
                 updateContentHeight();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index dc1a191..e89645d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -98,9 +98,9 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.HeadsUpNotificationViewControllerEmptyImpl;
-import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
-import com.android.systemui.statusbar.notification.HeadsUpTouchHelper.HeadsUpNotificationViewController;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpNotificationViewControllerEmptyImpl;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpTouchHelper.HeadsUpNotificationViewController;
 import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
@@ -138,8 +138,8 @@
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController;
 import com.android.systemui.statusbar.policy.SplitShadeStateController;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -1222,7 +1222,7 @@
 
     public void goToFullShade(long delay) {
         SceneContainerFlag.assertInLegacyMode();
-        mView.goToFullShade(delay);
+        mView.animateGoToFullShade(delay);
     }
 
     public void setOverScrollAmount(float amount, boolean onTop, boolean animate,
@@ -1603,6 +1603,12 @@
         }
     }
 
+    /** Sets whether the NSSL is displayed over the unoccluded Lockscreen. */
+    public void setOnLockscreen(boolean isOnLockscreen) {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
+        mNotificationListContainer.setOnLockscreen(isOnLockscreen);
+    }
+
     /**
      * Set the maximum number of notifications that can currently be displayed
      */
@@ -2029,6 +2035,11 @@
         }
 
         @Override
+        public void setOnLockscreen(boolean isOnLockscreen) {
+            mView.setOnLockscreen(isOnLockscreen);
+        }
+
+        @Override
         public void setMaxDisplayedNotifications(int maxNotifications) {
             mView.setMaxDisplayedNotifications(maxNotifications);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
index ef14557..b2ffa4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
@@ -33,7 +33,7 @@
 import com.android.systemui.statusbar.notification.NotificationFadeAware.FadeOptimizedNotification;
 import com.android.systemui.statusbar.notification.PropertyAnimator;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
-import com.android.systemui.statusbar.policy.HeadsUpUtil;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpUtil;
 
 import java.io.PrintWriter;
 import java.lang.reflect.Field;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
index 4a55dfa..ea71460 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
@@ -118,8 +118,12 @@
                     }
 
                     launch {
-                        viewModel.getMaxNotifications(calculateMaxNotifications).collect {
-                            controller.setMaxDisplayedNotifications(it)
+                        viewModel.getLockscreenDisplayConfig(calculateMaxNotifications).collect {
+                            (isOnLockscreen, maxNotifications) ->
+                            if (SceneContainerFlag.isEnabled) {
+                                controller.setOnLockscreen(isOnLockscreen)
+                            }
+                            controller.setMaxDisplayedNotifications(maxNotifications)
                         }
                     }
 
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 fb60f26..01efd5d 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
@@ -43,6 +43,7 @@
 import com.android.systemui.keyguard.shared.model.StatusBarState.SHADE
 import com.android.systemui.keyguard.shared.model.StatusBarState.SHADE_LOCKED
 import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToPrimaryBouncerTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
 import com.android.systemui.keyguard.ui.viewmodel.AodToGoneTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.AodToLockscreenTransitionViewModel
@@ -124,6 +125,8 @@
     private val notificationStackAppearanceInteractor: NotificationStackAppearanceInteractor,
     private val alternateBouncerToGoneTransitionViewModel:
         AlternateBouncerToGoneTransitionViewModel,
+    private val alternateBouncerToPrimaryBouncerTransitionViewModel:
+        AlternateBouncerToPrimaryBouncerTransitionViewModel,
     private val aodToGoneTransitionViewModel: AodToGoneTransitionViewModel,
     private val aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
     private val aodToOccludedTransitionViewModel: AodToOccludedTransitionViewModel,
@@ -560,6 +563,7 @@
             lockscreenToGoneTransitionViewModel.notificationAlpha(viewState),
             lockscreenToOccludedTransitionViewModel.lockscreenAlpha,
             lockscreenToPrimaryBouncerTransitionViewModel.lockscreenAlpha,
+            alternateBouncerToPrimaryBouncerTransitionViewModel.lockscreenAlpha,
             occludedToAodTransitionViewModel.lockscreenAlpha,
             occludedToGoneTransitionViewModel.notificationAlpha(viewState),
             occludedToLockscreenTransitionViewModel.lockscreenAlpha,
@@ -718,9 +722,11 @@
      * When expanding or when the user is interacting with the shade, keep the count stable; do not
      * emit a value.
      */
-    fun getMaxNotifications(calculateSpace: (Float, Boolean) -> Int): Flow<Int> {
+    fun getLockscreenDisplayConfig(
+        calculateSpace: (Float, Boolean) -> Int
+    ): Flow<LockscreenDisplayConfig> {
         val showLimitedNotifications = isOnLockscreenWithoutShade
-        val showUnlimitedNotifications =
+        val showUnlimitedNotificationsAndIsOnLockScreen =
             combine(
                 isOnLockscreen,
                 keyguardInteractor.statusBarState,
@@ -730,28 +736,42 @@
                     )
                     .onStart { emit(false) },
             ) { isOnLockscreen, statusBarState, showAllNotifications ->
-                statusBarState == SHADE_LOCKED || !isOnLockscreen || showAllNotifications
+                (statusBarState == SHADE_LOCKED || !isOnLockscreen || showAllNotifications) to
+                    isOnLockscreen
             }
 
+        @Suppress("UNCHECKED_CAST")
         return combineTransform(
                 showLimitedNotifications,
-                showUnlimitedNotifications,
+                showUnlimitedNotificationsAndIsOnLockScreen,
                 shadeInteractor.isUserInteracting,
                 availableHeight,
                 interactor.notificationStackChanged,
                 interactor.useExtraShelfSpace,
             ) { flows ->
                 val showLimitedNotifications = flows[0] as Boolean
-                val showUnlimitedNotifications = flows[1] as Boolean
+                val (showUnlimitedNotifications, isOnLockscreen) =
+                    flows[1] as Pair<Boolean, Boolean>
                 val isUserInteracting = flows[2] as Boolean
                 val availableHeight = flows[3] as Float
                 val useExtraShelfSpace = flows[5] as Boolean
 
                 if (!isUserInteracting) {
                     if (showLimitedNotifications) {
-                        emit(calculateSpace(availableHeight, useExtraShelfSpace))
+                        emit(
+                            LockscreenDisplayConfig(
+                                isOnLockscreen = isOnLockscreen,
+                                maxNotifications =
+                                    calculateSpace(availableHeight, useExtraShelfSpace),
+                            )
+                        )
                     } else if (showUnlimitedNotifications) {
-                        emit(-1)
+                        emit(
+                            LockscreenDisplayConfig(
+                                isOnLockscreen = isOnLockscreen,
+                                maxNotifications = -1,
+                            )
+                        )
                     }
                 }
             }
@@ -775,9 +795,9 @@
         SceneContainerFlag.assertInLegacyMode()
 
         return combine(
-            getMaxNotifications(calculateMaxNotifications).map {
-                val height = calculateHeight(it)
-                if (it == 0) {
+            getLockscreenDisplayConfig(calculateMaxNotifications).map { (_, maxNotifications) ->
+                val height = calculateHeight(maxNotifications)
+                if (maxNotifications == 0) {
                     height - shelfHeight
                 } else {
                     height
@@ -815,4 +835,13 @@
          */
         data class FloatAtEnd(val width: Int) : HorizontalPosition
     }
+
+    /**
+     * Data class representing a configuration for displaying Notifications on the Lockscreen.
+     *
+     * @param isOnLockscreen is the user on the lockscreen
+     * @param maxNotifications Limit for the max number of top-level Notifications to be displayed.
+     *   A value of -1 indicates no limit.
+     */
+    data class LockscreenDisplayConfig(val isOnLockscreen: Boolean, val maxNotifications: Int)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.kt
new file mode 100644
index 0000000..636e1c4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.statusbar.phone
+
+import android.content.Context
+import android.view.MotionEvent
+import com.android.systemui.statusbar.AutoHideUiElement
+import java.io.PrintWriter
+
+/**
+ * Controls the auto-hide behavior of system bars (status bar, navigation bar).
+ *
+ * This interface provides methods to manage the auto-hide schedule of system bars, allowing them to
+ * be shown or hidden.
+ */
+interface AutoHideController {
+    /**
+     * Sets a [AutoHideUiElement] status bar that should be controlled by the [AutoHideController].
+     */
+    fun setStatusBar(element: AutoHideUiElement)
+
+    /**
+     * Sets a [AutoHideUiElement] navigation bar that should be controlled by the
+     * [AutoHideController].
+     */
+    fun setNavigationBar(element: AutoHideUiElement)
+
+    /** Resumes the auto-hide behavior that was previously suspended. */
+    fun resumeSuspendedAutoHide()
+
+    /** Suspends the auto-hide behavior. */
+    fun suspendAutoHide()
+
+    /** Schedules or cancels auto hide behavior based on current system bar state. */
+    fun touchAutoHide()
+
+    /** Hides system bars on user touch if the interaction requires them to be hidden. */
+    fun checkUserAutoHide(event: MotionEvent)
+
+    /** Called when work should stop and resources should be released. */
+    fun stop()
+
+    /** Dumps the current state of the [AutoHideController] */
+    fun dump(pw: PrintWriter)
+
+    /** Injectable factory for creating a [AutoHideController]. */
+    interface Factory {
+        /** Create an [AutoHideController] */
+        fun create(context: Context): AutoHideController
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerImpl.java
similarity index 88%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerImpl.java
index 1358cfd..4fbfbb2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -28,7 +28,6 @@
 
 import androidx.annotation.NonNull;
 
-import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.statusbar.AutoHideUiElement;
 
@@ -36,9 +35,7 @@
 
 import javax.inject.Inject;
 
-/** A controller to control all auto-hide things. Also see {@link AutoHideUiElement}. */
-@SysUISingleton
-public class AutoHideController {
+public class AutoHideControllerImpl implements AutoHideController {
     private static final String TAG = "AutoHideController";
     private static final int AUTO_HIDE_TIMEOUT_MS = 2250;
     private static final int USER_AUTO_HIDE_TIMEOUT_MS = 350;
@@ -61,7 +58,7 @@
     };
 
     @Inject
-    public AutoHideController(Context context,
+    public AutoHideControllerImpl(Context context,
             @Main Handler handler,
             IWindowManager iWindowManager) {
         mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
@@ -70,18 +67,12 @@
         mDisplayId = context.getDisplayId();
     }
 
-    /**
-     * Sets a {@link AutoHideUiElement} status bar that should be controlled by the
-     * {@link AutoHideController}.
-     */
+    @Override
     public void setStatusBar(AutoHideUiElement element) {
         mStatusBar = element;
     }
 
-    /**
-     * Sets a {@link AutoHideUiElement} navigation bar that should be controlled by the
-     * {@link AutoHideController}.
-     */
+    @Override
     public void setNavigationBar(AutoHideUiElement element) {
         mNavigationBar = element;
     }
@@ -102,6 +93,7 @@
         }
     }
 
+    @Override
     public void resumeSuspendedAutoHide() {
         if (mAutoHideSuspended) {
             scheduleAutoHide();
@@ -112,6 +104,7 @@
         }
     }
 
+    @Override
     public void suspendAutoHide() {
         mHandler.removeCallbacks(mAutoHide);
         Runnable checkBarModesRunnable = getCheckBarModesRunnable();
@@ -121,7 +114,7 @@
         mAutoHideSuspended = isAnyTransientBarShown();
     }
 
-    /** Schedules or cancels auto hide behavior based on current system bar state. */
+    @Override
     public void touchAutoHide() {
         // update transient bar auto hide
         if (isAnyTransientBarShown()) {
@@ -156,6 +149,7 @@
                 FLAG_CONTENT_CONTROLS);
     }
 
+    @Override
     public void checkUserAutoHide(MotionEvent event) {
         boolean shouldHide = isAnyTransientBarShown()
                 && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar.
@@ -196,6 +190,12 @@
         return false;
     }
 
+    @Override
+    public void stop() {
+        mHandler.removeCallbacks(mAutoHide);
+    }
+
+    @Override
     public void dump(@NonNull PrintWriter pw) {
         pw.println("AutoHideController:");
         pw.println("\tmAutoHideSuspended=" + mAutoHideSuspended);
@@ -205,10 +205,7 @@
         pw.println("\tgetUserAutoHideTimeout=" + getUserAutoHideTimeout());
     }
 
-    /**
-     * Injectable factory for creating a {@link AutoHideController}.
-     */
-    public static class Factory {
+    public static class Factory implements AutoHideController.Factory {
         private final Handler mHandler;
         private final IWindowManager mIWindowManager;
 
@@ -219,8 +216,9 @@
         }
 
         /** Create an {@link AutoHideController} */
+        @Override
         public AutoHideController create(Context context) {
-            return new AutoHideController(context, mHandler, mIWindowManager);
+            return new AutoHideControllerImpl(context, mHandler, mIWindowManager);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt
new file mode 100644
index 0000000..744f969
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt
@@ -0,0 +1,73 @@
+/*
+ * 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.statusbar.phone
+
+import android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.display.data.repository.DisplayRepository
+import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
+import com.android.systemui.display.data.repository.PerDisplayStore
+import com.android.systemui.display.data.repository.PerDisplayStoreImpl
+import com.android.systemui.display.data.repository.SingleDisplayStore
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+
+/** Provides per display instances of [AutoHideController] */
+interface AutoHideControllerStore : PerDisplayStore<AutoHideController>
+
+@SysUISingleton
+class MultiDisplayAutoHideControllerStore
+@Inject
+constructor(
+    @Background backgroundApplicationScope: CoroutineScope,
+    displayRepository: DisplayRepository,
+    private val displayWindowPropertiesRepository: DisplayWindowPropertiesRepository,
+    private val autoHideControllerFactory: AutoHideControllerImpl.Factory,
+) :
+    AutoHideControllerStore,
+    PerDisplayStoreImpl<AutoHideController>(backgroundApplicationScope, displayRepository) {
+
+    init {
+        StatusBarConnectedDisplays.assertInNewMode()
+    }
+
+    override fun createInstanceForDisplay(displayId: Int): AutoHideController {
+        val displayWindowProperties =
+            displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR)
+        return autoHideControllerFactory.create(displayWindowProperties.context)
+    }
+
+    override suspend fun onDisplayRemovalAction(instance: AutoHideController) {
+        instance.stop()
+    }
+
+    override val instanceClass = AutoHideController::class.java
+}
+
+@SysUISingleton
+class SingleDisplayAutoHideControllerStore
+@Inject
+constructor(defaultController: AutoHideController) :
+    AutoHideControllerStore,
+    PerDisplayStore<AutoHideController> by SingleDisplayStore(defaultController) {
+
+    init {
+        StatusBarConnectedDisplays.assertInLegacyMode()
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index 5209d0f..7f95fb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -66,7 +66,7 @@
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index db29493..c6af328 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -221,7 +221,7 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.statusbar.policy.ExtensionController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
@@ -401,7 +401,7 @@
     private final KeyguardBypassController mKeyguardBypassController;
     private final KeyguardStateController mKeyguardStateController;
     private final HeadsUpManager mHeadsUpManager;
-    private final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
+    private final ShadeTouchableRegionManager mShadeTouchableRegionManager;
     private final FalsingCollector mFalsingCollector;
     private final FalsingManager mFalsingManager;
     private final BroadcastDispatcher mBroadcastDispatcher;
@@ -681,7 +681,7 @@
             KeyguardIndicationController keyguardIndicationController,
             DemoModeController demoModeController,
             Lazy<NotificationShadeDepthController> notificationShadeDepthControllerLazy,
-            StatusBarTouchableRegionManager statusBarTouchableRegionManager,
+            ShadeTouchableRegionManager shadeTouchableRegionManager,
             BrightnessSliderController.Factory brightnessSliderFactory,
             ScreenOffAnimationController screenOffAnimationController,
             WallpaperController wallpaperController,
@@ -724,7 +724,7 @@
         mHeadsUpManager = headsUpManager;
         mBackActionInteractor = backActionInteractor;
         mKeyguardIndicationController = keyguardIndicationController;
-        mStatusBarTouchableRegionManager = statusBarTouchableRegionManager;
+        mShadeTouchableRegionManager = shadeTouchableRegionManager;
         mFalsingCollector = falsingCollector;
         mFalsingManager = falsingManager;
         mBroadcastDispatcher = broadcastDispatcher;
@@ -1232,7 +1232,7 @@
             mStatusBarInitializer.initializeStatusBar();
         }
 
-        mStatusBarTouchableRegionManager.setup(getNotificationShadeWindowView());
+        mShadeTouchableRegionManager.setup(getNotificationShadeWindowView());
 
         if (!StatusBarConnectedDisplays.isEnabled()) {
             createNavigationBar(result);
@@ -1856,10 +1856,10 @@
             pw.println("  mHeadsUpManager: null");
         }
 
-        if (mStatusBarTouchableRegionManager != null) {
-            mStatusBarTouchableRegionManager.dump(pw, args);
+        if (mShadeTouchableRegionManager != null) {
+            mShadeTouchableRegionManager.dump(pw, args);
         } else {
-            pw.println("  mStatusBarTouchableRegionManager: null");
+            pw.println("  mShadeTouchableRegionManager: null");
         }
 
         if (mLightBarController != null) {
@@ -2566,7 +2566,7 @@
             dismissVolumeDialog();
             mWakeUpCoordinator.setFullyAwake(false);
             mKeyguardBypassController.onStartedGoingToSleep();
-            mStatusBarTouchableRegionManager.updateTouchableRegion();
+            mShadeTouchableRegionManager.updateTouchableRegion();
 
             // The unlocked screen off and fold to aod animations might use our LightRevealScrim -
             // we need to be expanded for it to be visible.
@@ -2655,7 +2655,7 @@
             // once we fully woke up.
             updateRevealEffect(true /* wakingUp */);
             updateNotificationPanelTouchState();
-            mStatusBarTouchableRegionManager.updateTouchableRegion();
+            mShadeTouchableRegionManager.updateTouchableRegion();
 
             // If we are waking up during the screen off animation, we should undo making the
             // expanded visible (we did that so the LightRevealScrim would be visible).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index ec92990..57e26d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -54,8 +54,8 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.OnHeadsUpChangedListener;
 import com.android.systemui.util.Assert;
 import com.android.systemui.util.CopyOnLoopListenerSet;
 import com.android.systemui.util.IListenerSet;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 8de03d8..677ed9f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -37,19 +37,20 @@
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.HeadsUpStatusBarView;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.core.StatusBarRootModernization;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.SourceType;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation;
 import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.phone.fragment.dagger.HomeStatusBarScope;
 import com.android.systemui.statusbar.policy.Clock;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.util.ViewController;
 
 import java.util.ArrayList;
@@ -249,10 +250,14 @@
                 updateParentClipping(false /* shouldClip */);
                 mView.setVisibility(View.VISIBLE);
                 show(mView);
-                hide(mClockView, View.INVISIBLE);
+                if (!StatusBarRootModernization.isEnabled()) {
+                    hide(mClockView, View.INVISIBLE);
+                }
                 mOperatorNameViewOptional.ifPresent(view -> hide(view, View.INVISIBLE));
             } else {
-                show(mClockView);
+                if (!StatusBarRootModernization.isEnabled()) {
+                    show(mClockView);
+                }
                 mOperatorNameViewOptional.ifPresent(this::show);
                 hide(mView, View.GONE, () -> {
                     updateParentClipping(true /* shouldClip */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.kt
index a6374a6..cd9b9d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone
 
+import android.content.Context
 import android.view.WindowInsetsController
 import com.android.internal.colorextraction.ColorExtractor
 import com.android.internal.view.AppearanceRegion
@@ -64,4 +65,8 @@
         scrimBehindAlpha: Float,
         scrimInFrontColor: ColorExtractor.GradientColors,
     )
+
+    fun interface Factory {
+        fun create(context: Context): LightBarController
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java
index ccb9a11..ea67f1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java
@@ -22,6 +22,7 @@
 import static com.android.systemui.shared.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
 import static com.android.systemui.shared.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
 
+import android.content.Context;
 import android.graphics.Rect;
 import android.util.Log;
 import android.view.Display;
@@ -34,12 +35,15 @@
 
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
 import com.android.internal.view.AppearanceRegion;
+import com.android.systemui.dagger.qualifiers.Application;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.statusbar.data.model.StatusBarAppearance;
+import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore;
 import com.android.systemui.statusbar.data.repository.StatusBarModePerDisplayRepository;
+import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.util.Compile;
 import com.android.systemui.util.kotlin.JavaAdapterKt;
@@ -55,6 +59,8 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
+import javax.inject.Inject;
+
 /**
  * Controls how light status bar flag applies to the icons.
  */
@@ -67,6 +73,7 @@
 
     private static final float NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD = 0.1f;
 
+    private final int mDisplayId;
     private final CoroutineScope mCoroutineScope;
     private final SysuiDarkIconDispatcher mStatusBarIconController;
     private final BatteryController mBatteryController;
@@ -140,6 +147,7 @@
             DumpManager dumpManager,
             @Main CoroutineContext mainContext,
             BiometricUnlockController biometricUnlockController) {
+        mDisplayId = displayId;
         mCoroutineScope = coroutineScope;
         mStatusBarIconController = (SysuiDarkIconDispatcher) darkIconDispatcher;
         mBatteryController = batteryController;
@@ -155,7 +163,12 @@
 
     @Override
     public void start() {
-        mDumpManager.registerCriticalDumpable(mDumpableName, this);
+        if (mDisplayId == Display.DEFAULT_DISPLAY) {
+            // Can only register on default display, because NavigationBar creates its own instance
+            // as well as PerDisplayStore.
+            // TODO: b/380394368 - make sure there is only one instance per display.
+            mDumpManager.registerCriticalDumpable(mDumpableName, this);
+        }
         mBatteryController.addCallback(this);
         mNavigationMode = mNavModeController.addListener(mNavigationModeListener);
         JavaAdapterKt.collectFlow(
@@ -490,4 +503,40 @@
                 DarkIconDispatcher darkIconDispatcher,
                 StatusBarModePerDisplayRepository statusBarModePerDisplayRepository);
     }
+
+    public static class LegacyFactory implements LightBarController.Factory {
+
+        private final Factory mFactory;
+        private final CoroutineScope mApplicationScope;
+        private final DarkIconDispatcherStore mDarkIconDispatcherStore;
+        private final StatusBarModeRepositoryStore mStatusBarModeRepositoryStore;
+
+        @Inject
+        public LegacyFactory(
+                LightBarControllerImpl.Factory factory,
+                @Application CoroutineScope applicationScope,
+                DarkIconDispatcherStore darkIconDispatcherStore,
+                StatusBarModeRepositoryStore statusBarModeRepositoryStore) {
+            mFactory = factory;
+            mApplicationScope = applicationScope;
+            mDarkIconDispatcherStore = darkIconDispatcherStore;
+            mStatusBarModeRepositoryStore = statusBarModeRepositoryStore;
+        }
+
+        @NonNull
+        @Override
+        public LightBarController create(@NonNull Context context) {
+            // TODO: b/380394368 - Make sure correct per display instances are used.
+            LightBarControllerImpl lightBarController = mFactory.create(
+                    context.getDisplayId(),
+                    mApplicationScope,
+                    mDarkIconDispatcherStore.getDefaultDisplay(),
+                    mStatusBarModeRepositoryStore.getDefaultDisplay()
+            );
+            // Calling start() manually to keep the legacy behavior. Before, LightBarControllerImpl
+            // was doing work in the constructor, which moved to start().
+            lightBarController.start();
+            return lightBarController;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeTouchableRegionManager.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeTouchableRegionManager.java
index d2c2003..bea8397 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeTouchableRegionManager.java
@@ -47,8 +47,8 @@
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.OnHeadsUpChangedListener;
 import com.android.systemui.util.kotlin.JavaAdapter;
 
 import java.io.PrintWriter;
@@ -62,7 +62,7 @@
  * of HeadsUpNotifications.
  */
 @SysUISingleton
-public final class StatusBarTouchableRegionManager implements Dumpable {
+public final class ShadeTouchableRegionManager implements Dumpable {
     private static final String TAG = "TouchableRegionManager";
 
     private final Context mContext;
@@ -90,7 +90,7 @@
     private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener;
 
     @Inject
-    public StatusBarTouchableRegionManager(
+    public ShadeTouchableRegionManager(
             Context context,
             NotificationShadeWindowController notificationShadeWindowController,
             ConfigurationController configurationController,
@@ -165,7 +165,7 @@
 
     @Override
     public void dump(PrintWriter pw, String[] args) {
-        pw.println("StatusBarTouchableRegionManager state:");
+        pw.println("ShadeTouchableRegionManager state:");
         pw.print("  mTouchableRegion=");
         pw.println(mTouchableRegion);
     }
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 aef26de..bd1360f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -818,7 +818,10 @@
      * dragging it and translation should be deferred {@see KeyguardBouncer#show(boolean, boolean)}
      */
     public void showPrimaryBouncer(boolean scrimmed) {
-        hideAlternateBouncer(false);
+        hideAlternateBouncer(
+                /* updateScrim= */ false,
+                // When the scene framework is on, don't ever clear the pending dismiss action from
+                /* clearDismissAction= */ !SceneContainerFlag.isEnabled());
         if (mKeyguardStateController.isShowing() && !isBouncerShowing()) {
             if (SceneContainerFlag.isEnabled()) {
                 mSceneInteractorLazy.get().changeScene(
@@ -1005,6 +1008,15 @@
 
     @Override
     public void hideAlternateBouncer(boolean updateScrim) {
+        hideAlternateBouncer(updateScrim, /* clearDismissAction= */ true);
+    }
+
+    @Override
+    public void hideAlternateBouncer(boolean updateScrim, boolean clearDismissAction) {
+        if (clearDismissAction) {
+            mKeyguardDismissActionInteractor.get().clearDismissAction();
+        }
+
         updateAlternateBouncerShowing(mAlternateBouncerInteractor.hide() && updateScrim);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index af98311..e33baf7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -79,8 +79,8 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowDragController;
 import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.HeadsUpUtil;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpUtil;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.wmshell.BubblesManager;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 79ea59c..b3cc047 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -69,7 +69,7 @@
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import java.util.Set;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
index 58386b0..4f32aaa26 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
@@ -35,7 +35,10 @@
 import com.android.systemui.statusbar.data.repository.PrivacyDotWindowControllerStoreModule
 import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore
 import com.android.systemui.statusbar.events.PrivacyDotViewControllerModule
+import com.android.systemui.statusbar.phone.AutoHideControllerStore
 import com.android.systemui.statusbar.phone.CentralSurfacesCommandQueueCallbacks
+import com.android.systemui.statusbar.phone.MultiDisplayAutoHideControllerStore
+import com.android.systemui.statusbar.phone.SingleDisplayAutoHideControllerStore
 import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.android.systemui.statusbar.window.data.repository.StatusBarWindowStateRepositoryStore
 import com.android.systemui.statusbar.window.data.repository.StatusBarWindowStateRepositoryStoreImpl
@@ -120,6 +123,7 @@
             statusBarModeRepositoryStore: StatusBarModeRepositoryStore,
             initializerStore: StatusBarInitializerStore,
             statusBarWindowControllerStore: StatusBarWindowControllerStore,
+            autoHideControllerStore: AutoHideControllerStore,
             statusBarOrchestratorFactory: StatusBarOrchestrator.Factory,
         ): StatusBarOrchestrator {
             return statusBarOrchestratorFactory.create(
@@ -129,6 +133,7 @@
                 statusBarModeRepositoryStore.defaultDisplay,
                 initializerStore.defaultDisplay,
                 statusBarWindowControllerStore.defaultDisplay,
+                autoHideControllerStore.defaultDisplay,
             )
         }
 
@@ -186,5 +191,32 @@
                 singleDisplayStoreLazy.get()
             }
         }
+
+        @Provides
+        @SysUISingleton
+        fun autoHideStore(
+            singleDisplayLazy: Lazy<SingleDisplayAutoHideControllerStore>,
+            multiDisplayLazy: Lazy<MultiDisplayAutoHideControllerStore>,
+        ): AutoHideControllerStore {
+            return if (StatusBarConnectedDisplays.isEnabled) {
+                multiDisplayLazy.get()
+            } else {
+                singleDisplayLazy.get()
+            }
+        }
+
+        @Provides
+        @SysUISingleton
+        @IntoMap
+        @ClassKey(AutoHideControllerStore::class)
+        fun storeAsCoreStartable(
+            multiDisplayLazy: Lazy<MultiDisplayAutoHideControllerStore>
+        ): CoreStartable {
+            return if (StatusBarConnectedDisplays.isEnabled) {
+                multiDisplayLazy.get()
+            } else {
+                CoreStartable.NOP
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index aac2cd1..78926c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -25,6 +25,7 @@
 import android.content.Context
 import android.view.View
 import androidx.annotation.VisibleForTesting
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.systemui.CoreStartable
 import com.android.systemui.Dumpable
@@ -58,7 +59,6 @@
 import java.util.concurrent.Executor
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 /** A controller to handle the ongoing call chip in the collapsed status bar. */
 @SysUISingleton
@@ -122,9 +122,9 @@
                             entry.sbn.uid,
                             entry.sbn.notification.extras.getInt(
                                 Notification.EXTRA_CALL_TYPE,
-                                -1
+                                -1,
                             ) == CALL_TYPE_ONGOING,
-                            statusBarSwipedAway = callNotificationInfo?.statusBarSwipedAway ?: false
+                            statusBarSwipedAway = callNotificationInfo?.statusBarSwipedAway ?: false,
                         )
                     if (newOngoingCallInfo == callNotificationInfo) {
                         return
@@ -236,7 +236,7 @@
                     bool1 = Flags.statusBarCallChipNotificationIcon()
                     bool2 = currentInfo.notificationIconView != null
                 },
-                { "Creating OngoingCallModel.InCall. notifIconFlag=$bool1 hasIcon=$bool2" }
+                { "Creating OngoingCallModel.InCall. notifIconFlag=$bool1 hasIcon=$bool2" },
             )
             val icon =
                 if (Flags.statusBarCallChipNotificationIcon()) {
@@ -288,7 +288,7 @@
                     str1 = notifModel.callType.name
                     bool1 = notifModel.statusBarChipIconView != null
                 },
-                { "NotifInteractorCallModel: key=$str1 when=$long1 callType=$str2 hasIcon=$bool1" }
+                { "NotifInteractorCallModel: key=$str1 when=$long1 callType=$str2 hasIcon=$bool1" },
             )
 
             val newOngoingCallInfo =
@@ -299,7 +299,7 @@
                     notifModel.contentIntent,
                     notifModel.uid,
                     isOngoing = true,
-                    statusBarSwipedAway = callNotificationInfo?.statusBarSwipedAway ?: false
+                    statusBarSwipedAway = callNotificationInfo?.statusBarSwipedAway ?: false,
                 )
             if (newOngoingCallInfo == callNotificationInfo) {
                 return
@@ -378,7 +378,7 @@
                     ActivityTransitionAnimator.Controller.fromView(
                         backgroundView,
                         InteractionJankMonitor.CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP,
-                    )
+                    ),
                 )
             }
         }
@@ -455,7 +455,7 @@
         /** True if the call is currently ongoing (as opposed to incoming, screening, etc.). */
         val isOngoing: Boolean,
         /** True if the user has swiped away the status bar while in this phone call. */
-        val statusBarSwipedAway: Boolean
+        val statusBarSwipedAway: Boolean,
     ) {
         /**
          * Returns true if the notification information has a valid call start time. See
@@ -472,6 +472,9 @@
     /**
      * Observer to tell us when the app that posted the ongoing call notification is visible so that
      * we don't show the call chip at the same time (since the timers could be out-of-sync).
+     *
+     * For a more recommended architecture implementation, see
+     * [com.android.systemui.activity.data.repository.ActivityManagerRepository].
      */
     inner class CallAppUidObserver : UidObserver() {
         /** True if the application managing the call is visible to the user. */
@@ -512,7 +515,7 @@
                     uidObserver,
                     ActivityManager.UID_OBSERVER_PROCSTATE,
                     ActivityManager.PROCESS_STATE_UNKNOWN,
-                    context.opPackageName
+                    context.opPackageName,
                 )
                 isRegistered = true
             } catch (se: SecurityException) {
@@ -537,7 +540,7 @@
             uid: Int,
             procState: Int,
             procStateSeq: Long,
-            capability: Int
+            capability: Int,
         ) {
             val currentCallAppUid = callAppUid ?: return
             if (uid != currentCallAppUid) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt
index b2a0272..a0cb829 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt
@@ -30,13 +30,13 @@
 @SysUISingleton
 class CollapsedStatusBarInteractor
 @Inject
-constructor(DisableFlagsInteractor: DisableFlagsInteractor) {
+constructor(disableFlagsInteractor: DisableFlagsInteractor) {
     /**
      * The visibilities of various status bar child views, based only on the information we received
      * from disable flags.
      */
     val visibilityViaDisableFlags: Flow<StatusBarDisableFlagsVisibilityModel> =
-        DisableFlagsInteractor.disableFlags.map {
+        disableFlagsInteractor.disableFlags.map {
             StatusBarDisableFlagsVisibilityModel(
                 isClockAllowed = it.isClockEnabled,
                 areNotificationIconsAllowed = it.areNotificationIconsEnabled,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
index 6a9b43c..c52275a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModel
 import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
 import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel
@@ -39,6 +40,7 @@
 import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState
 import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.Idle
 import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
+import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor
 import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
 import com.android.systemui.statusbar.phone.domain.interactor.LightsOutInteractor
 import com.android.systemui.statusbar.pipeline.shared.domain.interactor.CollapsedStatusBarInteractor
@@ -137,6 +139,7 @@
     collapsedStatusBarInteractor: CollapsedStatusBarInteractor,
     private val lightsOutInteractor: LightsOutInteractor,
     private val notificationsInteractor: ActiveNotificationsInteractor,
+    headsUpNotificationInteractor: HeadsUpNotificationInteractor,
     keyguardTransitionInteractor: KeyguardTransitionInteractor,
     keyguardInteractor: KeyguardInteractor,
     sceneInteractor: SceneInteractor,
@@ -222,27 +225,43 @@
             isHomeStatusBarAllowed && !isSecureCameraActive
         }
 
+    private val isAnyChipVisible =
+        if (StatusBarNotifChips.isEnabled) {
+            ongoingActivityChips.map { it.primary is OngoingActivityChipModel.Shown }
+        } else {
+            primaryOngoingActivityChip.map { it is OngoingActivityChipModel.Shown }
+        }
+
     override val isClockVisible: Flow<VisibilityModel> =
         combine(
             shouldHomeStatusBarBeVisible,
+            headsUpNotificationInteractor.showHeadsUpStatusBar,
             collapsedStatusBarInteractor.visibilityViaDisableFlags,
-        ) { shouldStatusBarBeVisible, visibilityViaDisableFlags ->
-            val showClock = shouldStatusBarBeVisible && visibilityViaDisableFlags.isClockAllowed
-            // TODO(b/364360986): Take CollapsedStatusBarFragment.clockHiddenMode into account.
-            VisibilityModel(showClock.toVisibilityInt(), visibilityViaDisableFlags.animate)
+        ) { shouldStatusBarBeVisible, showHeadsUp, visibilityViaDisableFlags ->
+            val showClock =
+                shouldStatusBarBeVisible && visibilityViaDisableFlags.isClockAllowed && !showHeadsUp
+            // Always use View.INVISIBLE here, so that animations work
+            VisibilityModel(showClock.toVisibleOrInvisible(), visibilityViaDisableFlags.animate)
         }
     override val isNotificationIconContainerVisible: Flow<VisibilityModel> =
         combine(
             shouldHomeStatusBarBeVisible,
+            isAnyChipVisible,
             collapsedStatusBarInteractor.visibilityViaDisableFlags,
-        ) { shouldStatusBarBeVisible, visibilityViaDisableFlags ->
+        ) { shouldStatusBarBeVisible, anyChipVisible, visibilityViaDisableFlags ->
             val showNotificationIconContainer =
-                shouldStatusBarBeVisible && visibilityViaDisableFlags.areNotificationIconsAllowed
+                if (anyChipVisible) {
+                    false
+                } else {
+                    shouldStatusBarBeVisible &&
+                        visibilityViaDisableFlags.areNotificationIconsAllowed
+                }
             VisibilityModel(
-                showNotificationIconContainer.toVisibilityInt(),
+                showNotificationIconContainer.toVisibleOrGone(),
                 visibilityViaDisableFlags.animate,
             )
         }
+
     private val isSystemInfoVisible =
         combine(
             shouldHomeStatusBarBeVisible,
@@ -250,7 +269,7 @@
         ) { shouldStatusBarBeVisible, visibilityViaDisableFlags ->
             val showSystemInfo =
                 shouldStatusBarBeVisible && visibilityViaDisableFlags.isSystemInfoAllowed
-            VisibilityModel(showSystemInfo.toVisibilityInt(), visibilityViaDisableFlags.animate)
+            VisibilityModel(showSystemInfo.toVisibleOrGone(), visibilityViaDisableFlags.animate)
         }
 
     override val systemInfoCombinedVis =
@@ -270,7 +289,11 @@
             )
 
     @View.Visibility
-    private fun Boolean.toVisibilityInt(): Int {
+    private fun Boolean.toVisibleOrGone(): Int {
         return if (this) View.VISIBLE else View.GONE
     }
+
+    // Similar to the above, but uses INVISIBLE in place of GONE
+    @View.Visibility
+    private fun Boolean.toVisibleOrInvisible(): Int = if (this) View.VISIBLE else View.INVISIBLE
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
index a115baa..52f80fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
@@ -24,6 +24,7 @@
 import android.media.MediaRouter.RouteInfo;
 import android.media.projection.MediaProjectionInfo;
 import android.media.projection.MediaProjectionManager;
+import android.media.projection.StopReason;
 import android.os.Handler;
 import android.util.ArrayMap;
 
@@ -190,7 +191,7 @@
         if (isProjection) {
             final MediaProjectionInfo projection = (MediaProjectionInfo) device.getTag();
             if (Objects.equals(mProjectionManager.getActiveProjectionInfo(), projection)) {
-                mProjectionManager.stopActiveProjection();
+                mProjectionManager.stopActiveProjection(StopReason.STOP_QS_TILE);
             } else {
                 mLogger.logStopCastingNoProjection(projection);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
index 616992e..56c9e9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
@@ -41,8 +41,8 @@
 import android.view.accessibility.AccessibilityNodeInfo
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction
 import android.widget.Button
-import com.android.systemui.res.R
 import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.res.R
 import com.android.systemui.shared.system.ActivityManagerWrapper
 import com.android.systemui.shared.system.DevicePolicyManagerWrapper
 import com.android.systemui.shared.system.PackageManagerWrapper
@@ -50,6 +50,7 @@
 import com.android.systemui.statusbar.NotificationUiAdjustment
 import com.android.systemui.statusbar.SmartReplyController
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.notification.logging.NotificationLogger
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil
 import com.android.systemui.statusbar.policy.InflatedSmartReplyState.SuppressedActions
@@ -63,40 +64,42 @@
 import javax.inject.Inject
 import kotlin.system.measureTimeMillis
 
-
 /** Returns whether we should show the smart reply view and its smart suggestions. */
 fun shouldShowSmartReplyView(
     entry: NotificationEntry,
-    smartReplyState: InflatedSmartReplyState
+    smartReplyState: InflatedSmartReplyState,
 ): Boolean {
-    if (smartReplyState.smartReplies == null &&
-            smartReplyState.smartActions == null) {
+    if (smartReplyState.smartReplies == null && smartReplyState.smartActions == null) {
         // There are no smart replies and no smart actions.
         return false
     }
     // If we are showing the spinner we don't want to add the buttons.
-    val showingSpinner = entry.sbn.notification.extras
-            .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false)
+    val showingSpinner =
+        entry.sbn.notification.extras.getBoolean(
+            Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER,
+            false,
+        )
     if (showingSpinner) {
         return false
     }
     // If we are keeping the notification around while sending we don't want to add the buttons.
-    return !entry.sbn.notification.extras
-            .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false)
+    return !entry.sbn.notification.extras.getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false)
 }
 
 /** Determines if two [InflatedSmartReplyState] are visually similar. */
 fun areSuggestionsSimilar(
     left: InflatedSmartReplyState?,
-    right: InflatedSmartReplyState?
-): Boolean = when {
-    left === right -> true
-    left == null || right == null -> false
-    left.hasPhishingAction != right.hasPhishingAction -> false
-    left.smartRepliesList != right.smartRepliesList -> false
-    left.suppressedActionIndices != right.suppressedActionIndices -> false
-    else -> !NotificationUiAdjustment.areDifferent(left.smartActionsList, right.smartActionsList)
-}
+    right: InflatedSmartReplyState?,
+): Boolean =
+    when {
+        left === right -> true
+        left == null || right == null -> false
+        left.hasPhishingAction != right.hasPhishingAction -> false
+        left.smartRepliesList != right.smartRepliesList -> false
+        left.suppressedActionIndices != right.suppressedActionIndices -> false
+        else ->
+            !NotificationUiAdjustment.areDifferent(left.smartActionsList, right.smartActionsList)
+    }
 
 interface SmartReplyStateInflater {
     fun inflateSmartReplyState(entry: NotificationEntry): InflatedSmartReplyState
@@ -106,181 +109,211 @@
         notifPackageContext: Context,
         entry: NotificationEntry,
         existingSmartReplyState: InflatedSmartReplyState?,
-        newSmartReplyState: InflatedSmartReplyState
+        newSmartReplyState: InflatedSmartReplyState,
     ): InflatedSmartReplyViewHolder
 }
 
-/*internal*/ class SmartReplyStateInflaterImpl @Inject constructor(
+/*internal*/ class SmartReplyStateInflaterImpl
+@Inject
+constructor(
     private val constants: SmartReplyConstants,
     private val activityManagerWrapper: ActivityManagerWrapper,
     private val packageManagerWrapper: PackageManagerWrapper,
     private val devicePolicyManagerWrapper: DevicePolicyManagerWrapper,
     private val smartRepliesInflater: SmartReplyInflater,
-    private val smartActionsInflater: SmartActionInflater
+    private val smartActionsInflater: SmartActionInflater,
 ) : SmartReplyStateInflater {
 
     override fun inflateSmartReplyState(entry: NotificationEntry): InflatedSmartReplyState =
-            chooseSmartRepliesAndActions(entry)
+        chooseSmartRepliesAndActions(entry)
 
     override fun inflateSmartReplyViewHolder(
         sysuiContext: Context,
         notifPackageContext: Context,
         entry: NotificationEntry,
         existingSmartReplyState: InflatedSmartReplyState?,
-        newSmartReplyState: InflatedSmartReplyState
+        newSmartReplyState: InflatedSmartReplyState,
     ): InflatedSmartReplyViewHolder {
         if (!shouldShowSmartReplyView(entry, newSmartReplyState)) {
             return InflatedSmartReplyViewHolder(
-                    null /* smartReplyView */,
-                    null /* smartSuggestionButtons */)
+                null /* smartReplyView */,
+                null, /* smartSuggestionButtons */
+            )
         }
 
         // Only block clicks if the smart buttons are different from the previous set - to avoid
         // scenarios where a user incorrectly cannot click smart buttons because the
         // notification is updated.
         val delayOnClickListener =
-                !areSuggestionsSimilar(existingSmartReplyState, newSmartReplyState)
+            !areSuggestionsSimilar(existingSmartReplyState, newSmartReplyState)
 
         val smartReplyView = SmartReplyView.inflate(sysuiContext, constants)
 
         val smartReplies = newSmartReplyState.smartReplies
         smartReplyView.setSmartRepliesGeneratedByAssistant(smartReplies?.fromAssistant ?: false)
-        val smartReplyButtons = smartReplies?.let {
-            smartReplies.choices.asSequence().mapIndexed { index, choice ->
-                smartRepliesInflater.inflateReplyButton(
+        val smartReplyButtons =
+            smartReplies?.let {
+                smartReplies.choices.asSequence().mapIndexed { index, choice ->
+                    smartRepliesInflater.inflateReplyButton(
                         smartReplyView,
                         entry,
                         smartReplies,
                         index,
                         choice,
-                        delayOnClickListener)
-            }
-        } ?: emptySequence()
+                        delayOnClickListener,
+                    )
+                }
+            } ?: emptySequence()
 
-        val smartActionButtons = newSmartReplyState.smartActions?.let { smartActions ->
-            val themedPackageContext =
+        val smartActionButtons =
+            newSmartReplyState.smartActions?.let { smartActions ->
+                val themedPackageContext =
                     ContextThemeWrapper(notifPackageContext, sysuiContext.theme)
-            smartActions.actions.asSequence()
+                smartActions.actions
+                    .asSequence()
                     .filter { it.actionIntent != null }
                     .mapIndexed { index, action ->
                         smartActionsInflater.inflateActionButton(
-                                smartReplyView,
-                                entry,
-                                smartActions,
-                                index,
-                                action,
-                                delayOnClickListener,
-                                themedPackageContext)
+                            smartReplyView,
+                            entry,
+                            smartActions,
+                            index,
+                            action,
+                            delayOnClickListener,
+                            themedPackageContext,
+                        )
                     }
-        } ?: emptySequence()
+            } ?: emptySequence()
 
         return InflatedSmartReplyViewHolder(
-                smartReplyView,
-                (smartReplyButtons + smartActionButtons).toList())
+            smartReplyView,
+            (smartReplyButtons + smartActionButtons).toList(),
+        )
     }
 
     /**
      * Chose what smart replies and smart actions to display. App generated suggestions take
-     * precedence. So if the app provides any smart replies, we don't show any
-     * replies or actions generated by the NotificationAssistantService (NAS), and if the app
-     * provides any smart actions we also don't show any NAS-generated replies or actions.
+     * precedence. So if the app provides any smart replies, we don't show any replies or actions
+     * generated by the NotificationAssistantService (NAS), and if the app provides any smart
+     * actions we also don't show any NAS-generated replies or actions.
      */
     fun chooseSmartRepliesAndActions(entry: NotificationEntry): InflatedSmartReplyState {
         val notification = entry.sbn.notification
         val remoteInputActionPair = notification.findRemoteInputActionPair(false /* freeform */)
         val freeformRemoteInputActionPair =
-                notification.findRemoteInputActionPair(true /* freeform */)
+            notification.findRemoteInputActionPair(true /* freeform */)
         if (!constants.isEnabled) {
             if (DEBUG) {
-                Log.d(TAG, "Smart suggestions not enabled, not adding suggestions for " +
-                        entry.sbn.key)
+                Log.d(
+                    TAG,
+                    "Smart suggestions not enabled, not adding suggestions for " + entry.sbn.key,
+                )
             }
             return InflatedSmartReplyState(null, null, null, false)
         }
         // Only use smart replies from the app if they target P or above. We have this check because
         // the smart reply API has been used for other things (Wearables) in the past. The API to
         // add smart actions is new in Q so it doesn't require a target-sdk check.
-        val enableAppGeneratedSmartReplies = (!constants.requiresTargetingP() ||
-                entry.targetSdk >= Build.VERSION_CODES.P)
+        val enableAppGeneratedSmartReplies =
+            (!constants.requiresTargetingP() || entry.targetSdk >= Build.VERSION_CODES.P)
         val appGeneratedSmartActions = notification.contextualActions
 
-        var smartReplies: SmartReplies? = when {
-            enableAppGeneratedSmartReplies -> remoteInputActionPair?.let { pair ->
-                pair.second.actionIntent?.let { actionIntent ->
-                    if (pair.first.choices?.isNotEmpty() == true)
-                        SmartReplies(
-                                pair.first.choices.asList(),
-                                pair.first,
-                                actionIntent,
-                                false /* fromAssistant */)
-                    else null
-                }
+        var smartReplies: SmartReplies? =
+            when {
+                enableAppGeneratedSmartReplies ->
+                    remoteInputActionPair?.let { pair ->
+                        pair.second.actionIntent?.let { actionIntent ->
+                            if (pair.first.choices?.isNotEmpty() == true)
+                                SmartReplies(
+                                    pair.first.choices.asList(),
+                                    pair.first,
+                                    actionIntent,
+                                    false, /* fromAssistant */
+                                )
+                            else null
+                        }
+                    }
+                else -> null
             }
-            else -> null
-        }
-        var smartActions: SmartActions? = when {
-            appGeneratedSmartActions.isNotEmpty() ->
-                SmartActions(appGeneratedSmartActions, false /* fromAssistant */)
-            else -> null
-        }
+        var smartActions: SmartActions? =
+            when {
+                appGeneratedSmartActions.isNotEmpty() ->
+                    SmartActions(appGeneratedSmartActions, false /* fromAssistant */)
+                else -> null
+            }
         // Apps didn't provide any smart replies / actions, use those from NAS (if any).
         if (smartReplies == null && smartActions == null) {
             val entryReplies = entry.smartReplies
             val entryActions = entry.smartActions
-            if (entryReplies.isNotEmpty() &&
+            if (
+                entryReplies.isNotEmpty() &&
                     freeformRemoteInputActionPair != null &&
                     freeformRemoteInputActionPair.second.allowGeneratedReplies &&
-                    freeformRemoteInputActionPair.second.actionIntent != null) {
-                smartReplies = SmartReplies(
+                    freeformRemoteInputActionPair.second.actionIntent != null
+            ) {
+                smartReplies =
+                    SmartReplies(
                         entryReplies,
                         freeformRemoteInputActionPair.first,
                         freeformRemoteInputActionPair.second.actionIntent,
-                        true /* fromAssistant */)
+                        true, /* fromAssistant */
+                    )
             }
-            if (entryActions.isNotEmpty() &&
-                    notification.allowSystemGeneratedContextualActions) {
-                val systemGeneratedActions: List<Notification.Action> = when {
-                    activityManagerWrapper.isLockTaskKioskModeActive ->
-                        // Filter actions if we're in kiosk-mode - we don't care about screen
-                        // pinning mode, since notifications aren't shown there anyway.
-                        filterAllowlistedLockTaskApps(entryActions)
-                    else -> entryActions
-                }
+            if (entryActions.isNotEmpty() && notification.allowSystemGeneratedContextualActions) {
+                val systemGeneratedActions: List<Notification.Action> =
+                    when {
+                        activityManagerWrapper.isLockTaskKioskModeActive ->
+                            // Filter actions if we're in kiosk-mode - we don't care about screen
+                            // pinning mode, since notifications aren't shown there anyway.
+                            filterAllowlistedLockTaskApps(entryActions)
+                        else -> entryActions
+                    }
                 smartActions = SmartActions(systemGeneratedActions, true /* fromAssistant */)
             }
         }
-        val hasPhishingAction = smartActions?.actions?.any {
-            it.isContextual && it.semanticAction ==
-                    Notification.Action.SEMANTIC_ACTION_CONVERSATION_IS_PHISHING
-        } ?: false
+        val hasPhishingAction =
+            smartActions?.actions?.any {
+                it.isContextual &&
+                    it.semanticAction ==
+                        Notification.Action.SEMANTIC_ACTION_CONVERSATION_IS_PHISHING
+            } ?: false
         var suppressedActions: SuppressedActions? = null
         if (hasPhishingAction) {
             // If there is a phishing action, calculate the indices of the actions with RemoteInput
             //  as those need to be hidden from the view.
-            val suppressedActionIndices = notification.actions.mapIndexedNotNull { index, action ->
-                if (action.remoteInputs?.isNotEmpty() == true) index else null
-            }
+            val suppressedActionIndices =
+                notification.actions.mapIndexedNotNull { index, action ->
+                    if (action.remoteInputs?.isNotEmpty() == true) index else null
+                }
             suppressedActions = SuppressedActions(suppressedActionIndices)
         }
-        return InflatedSmartReplyState(smartReplies, smartActions, suppressedActions,
-                hasPhishingAction)
+        return InflatedSmartReplyState(
+            smartReplies,
+            smartActions,
+            suppressedActions,
+            hasPhishingAction,
+        )
     }
 
     /**
-     * Filter actions so that only actions pointing to allowlisted apps are permitted.
-     * This filtering is only meaningful when in lock-task mode.
+     * Filter actions so that only actions pointing to allowlisted apps are permitted. This
+     * filtering is only meaningful when in lock-task mode.
      */
     private fun filterAllowlistedLockTaskApps(
         actions: List<Notification.Action>
-    ): List<Notification.Action> = actions.filter { action ->
-        //  Only allow actions that are explicit (implicit intents are not handled in lock-task
-        //  mode), and link to allowlisted apps.
-        action.actionIntent?.intent?.let { intent ->
-            packageManagerWrapper.resolveActivity(intent, 0 /* flags */)
-        }?.let { resolveInfo ->
-            devicePolicyManagerWrapper.isLockTaskPermitted(resolveInfo.activityInfo.packageName)
-        } ?: false
-    }
+    ): List<Notification.Action> =
+        actions.filter { action ->
+            //  Only allow actions that are explicit (implicit intents are not handled in lock-task
+            //  mode), and link to allowlisted apps.
+            action.actionIntent
+                ?.intent
+                ?.let { intent -> packageManagerWrapper.resolveActivity(intent, 0 /* flags */) }
+                ?.let { resolveInfo ->
+                    devicePolicyManagerWrapper.isLockTaskPermitted(
+                        resolveInfo.activityInfo.packageName
+                    )
+                } ?: false
+        }
 }
 
 interface SmartActionInflater {
@@ -291,7 +324,7 @@
         actionIndex: Int,
         action: Notification.Action,
         delayOnClickListener: Boolean,
-        packageContext: Context
+        packageContext: Context,
     ): Button
 }
 
@@ -310,28 +343,32 @@
         val bitmap: Bitmap?
         val durationMillis = measureTimeMillis {
             val source = ImageDecoder.createSource(packageContext.contentResolver, icon.uri)
-            bitmap = ImageDecoder.decodeBitmap(source) { decoder, _, _ ->
-                decoder.setTargetSize(targetSize, targetSize)
-                decoder.allocator = ImageDecoder.ALLOCATOR_DEFAULT
-            }
+            bitmap =
+                ImageDecoder.decodeBitmap(source) { decoder, _, _ ->
+                    decoder.setTargetSize(targetSize, targetSize)
+                    decoder.allocator = ImageDecoder.ALLOCATOR_DEFAULT
+                }
         }
         if (durationMillis > ICON_TASK_TIMEOUT_MS) {
             Log.w(TAG, "Loading $icon took ${durationMillis / 1000f} sec")
         }
         checkNotNull(bitmap) { "ImageDecoder.decodeBitmap() returned null" }
     }
-    val bitmap = runCatching {
-        iconTaskThreadPool.execute(bitmapTask)
-        bitmapTask.get(ICON_TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS)
-    }.getOrElse { ex ->
-        Log.e(TAG, "Failed to load $icon: $ex")
-        bitmapTask.cancel(true)
-        return null
-    }
+    val bitmap =
+        runCatching {
+                iconTaskThreadPool.execute(bitmapTask)
+                bitmapTask.get(ICON_TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS)
+            }
+            .getOrElse { ex ->
+                Log.e(TAG, "Failed to load $icon: $ex")
+                bitmapTask.cancel(true)
+                return null
+            }
     // TODO(b/288561520): rewrite Icon so that we don't need to duplicate this logic
     val bitmapDrawable = BitmapDrawable(packageContext.resources, bitmap)
-    val result = if (icon.type == Icon.TYPE_URI_ADAPTIVE_BITMAP)
-        AdaptiveIconDrawable(null, bitmapDrawable) else bitmapDrawable
+    val result =
+        if (icon.type == Icon.TYPE_URI_ADAPTIVE_BITMAP) AdaptiveIconDrawable(null, bitmapDrawable)
+        else bitmapDrawable
     if (icon.hasTint()) {
         result.mutate()
         result.setTintList(icon.tintList)
@@ -340,11 +377,13 @@
     return result
 }
 
-/* internal */ class SmartActionInflaterImpl @Inject constructor(
+/* internal */ class SmartActionInflaterImpl
+@Inject
+constructor(
     private val constants: SmartReplyConstants,
     private val activityStarter: ActivityStarter,
     private val smartReplyController: SmartReplyController,
-    private val headsUpManager: HeadsUpManager
+    private val headsUpManager: HeadsUpManager,
 ) : SmartActionInflater {
 
     override fun inflateActionButton(
@@ -354,17 +393,18 @@
         actionIndex: Int,
         action: Notification.Action,
         delayOnClickListener: Boolean,
-        packageContext: Context
+        packageContext: Context,
     ): Button =
-            (LayoutInflater.from(parent.context)
-                    .inflate(R.layout.smart_action_button, parent, false) as Button
-            ).apply {
+        (LayoutInflater.from(parent.context).inflate(R.layout.smart_action_button, parent, false)
+                as Button)
+            .apply {
                 text = action.title
 
-                // We received the Icon from the application - so use the Context of the application to
+                // We received the Icon from the application - so use the Context of the application
+                // to
                 // reference icon resources.
-                val newIconSize = context.resources
-                    .getDimensionPixelSize(R.dimen.smart_action_button_icon_size)
+                val newIconSize =
+                    context.resources.getDimensionPixelSize(R.dimen.smart_action_button_icon_size)
                 val iconDrawable =
                     loadIconDrawableWithTimeout(action.getIcon(), packageContext, newIconSize)
                         ?: GradientDrawable()
@@ -372,13 +412,15 @@
                 // Add the action icon to the Smart Action button.
                 setCompoundDrawablesRelative(iconDrawable, null, null, null)
 
-                val onClickListener = View.OnClickListener {
-                    onSmartActionClick(entry, smartActions, actionIndex, action)
-                }
+                val onClickListener =
+                    View.OnClickListener {
+                        onSmartActionClick(entry, smartActions, actionIndex, action)
+                    }
                 setOnClickListener(
-                        if (delayOnClickListener)
-                            DelayedOnClickListener(onClickListener, constants.onClickInitDelay)
-                        else onClickListener)
+                    if (delayOnClickListener)
+                        DelayedOnClickListener(onClickListener, constants.onClickInitDelay)
+                    else onClickListener
+                )
 
                 // Mark this as an Action button
                 (layoutParams as SmartReplyView.LayoutParams).mButtonType = SmartButtonType.ACTION
@@ -388,18 +430,31 @@
         entry: NotificationEntry,
         smartActions: SmartActions,
         actionIndex: Int,
-        action: Notification.Action
+        action: Notification.Action,
     ) =
-        if (smartActions.fromAssistant &&
-            SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY == action.semanticAction) {
-            entry.row.doSmartActionClick(entry.row.x.toInt() / 2,
-                entry.row.y.toInt() / 2, SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY)
-            smartReplyController
-                .smartActionClicked(entry, actionIndex, action, smartActions.fromAssistant)
+        if (
+            smartActions.fromAssistant &&
+                SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY == action.semanticAction
+        ) {
+            entry.row.doSmartActionClick(
+                entry.row.x.toInt() / 2,
+                entry.row.y.toInt() / 2,
+                SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY,
+            )
+            smartReplyController.smartActionClicked(
+                entry,
+                actionIndex,
+                action,
+                smartActions.fromAssistant,
+            )
         } else {
             activityStarter.startPendingIntentDismissingKeyguard(action.actionIntent, entry.row) {
-                smartReplyController
-                    .smartActionClicked(entry, actionIndex, action, smartActions.fromAssistant)
+                smartReplyController.smartActionClicked(
+                    entry,
+                    actionIndex,
+                    action,
+                    smartActions.fromAssistant,
+                )
             }
         }
 }
@@ -411,16 +466,18 @@
         smartReplies: SmartReplies,
         replyIndex: Int,
         choice: CharSequence,
-        delayOnClickListener: Boolean
+        delayOnClickListener: Boolean,
     ): Button
 }
 
-class SmartReplyInflaterImpl @Inject constructor(
+class SmartReplyInflaterImpl
+@Inject
+constructor(
     private val constants: SmartReplyConstants,
     private val keyguardDismissUtil: KeyguardDismissUtil,
     private val remoteInputManager: NotificationRemoteInputManager,
     private val smartReplyController: SmartReplyController,
-    private val context: Context
+    private val context: Context,
 ) : SmartReplyInflater {
 
     override fun inflateReplyButton(
@@ -429,37 +486,35 @@
         smartReplies: SmartReplies,
         replyIndex: Int,
         choice: CharSequence,
-        delayOnClickListener: Boolean
+        delayOnClickListener: Boolean,
     ): Button =
-            (LayoutInflater.from(parent.context)
-                    .inflate(R.layout.smart_reply_button, parent, false) as Button
-            ).apply {
+        (LayoutInflater.from(parent.context).inflate(R.layout.smart_reply_button, parent, false)
+                as Button)
+            .apply {
                 text = choice
-                val onClickListener = View.OnClickListener {
-                    onSmartReplyClick(
-                            entry,
-                            smartReplies,
-                            replyIndex,
-                            parent,
-                            this,
-                            choice)
-                }
-                setOnClickListener(
-                        if (delayOnClickListener)
-                            DelayedOnClickListener(onClickListener, constants.onClickInitDelay)
-                        else onClickListener)
-                accessibilityDelegate = object : View.AccessibilityDelegate() {
-                    override fun onInitializeAccessibilityNodeInfo(
-                        host: View,
-                        info: AccessibilityNodeInfo
-                    ) {
-                        super.onInitializeAccessibilityNodeInfo(host, info)
-                        val label = parent.resources
-                                .getString(R.string.accessibility_send_smart_reply)
-                        val action = AccessibilityAction(AccessibilityNodeInfo.ACTION_CLICK, label)
-                        info.addAction(action)
+                val onClickListener =
+                    View.OnClickListener {
+                        onSmartReplyClick(entry, smartReplies, replyIndex, parent, this, choice)
                     }
-                }
+                setOnClickListener(
+                    if (delayOnClickListener)
+                        DelayedOnClickListener(onClickListener, constants.onClickInitDelay)
+                    else onClickListener
+                )
+                accessibilityDelegate =
+                    object : View.AccessibilityDelegate() {
+                        override fun onInitializeAccessibilityNodeInfo(
+                            host: View,
+                            info: AccessibilityNodeInfo,
+                        ) {
+                            super.onInitializeAccessibilityNodeInfo(host, info)
+                            val label =
+                                parent.resources.getString(R.string.accessibility_send_smart_reply)
+                            val action =
+                                AccessibilityAction(AccessibilityNodeInfo.ACTION_CLICK, label)
+                            info.addAction(action)
+                        }
+                    }
                 // TODO: probably shouldn't do this here, bad API
                 // Mark this as a Reply button
                 (layoutParams as SmartReplyView.LayoutParams).mButtonType = SmartButtonType.REPLY
@@ -471,39 +526,52 @@
         replyIndex: Int,
         smartReplyView: SmartReplyView,
         button: Button,
-        choice: CharSequence
-    ) = keyguardDismissUtil.executeWhenUnlocked(!entry.isRowPinned) {
-        val canEditBeforeSend = constants.getEffectiveEditChoicesBeforeSending(
-                smartReplies.remoteInput.editChoicesBeforeSending)
-        if (canEditBeforeSend) {
-            remoteInputManager.activateRemoteInput(
+        choice: CharSequence,
+    ) =
+        keyguardDismissUtil.executeWhenUnlocked(!entry.isRowPinned) {
+            val canEditBeforeSend =
+                constants.getEffectiveEditChoicesBeforeSending(
+                    smartReplies.remoteInput.editChoicesBeforeSending
+                )
+            if (canEditBeforeSend) {
+                remoteInputManager.activateRemoteInput(
                     button,
                     arrayOf(smartReplies.remoteInput),
                     smartReplies.remoteInput,
                     smartReplies.pendingIntent,
-                    NotificationEntry.EditedSuggestionInfo(choice, replyIndex))
-        } else {
-            smartReplyController.smartReplySent(
+                    NotificationEntry.EditedSuggestionInfo(choice, replyIndex),
+                )
+            } else {
+                smartReplyController.smartReplySent(
                     entry,
                     replyIndex,
                     button.text,
                     NotificationLogger.getNotificationLocation(entry).toMetricsEventEnum(),
-                    false /* modifiedBeforeSending */)
-            entry.setHasSentReply()
-            try {
-                val intent = createRemoteInputIntent(smartReplies, choice)
-                val opts = ActivityOptions.makeBasic()
-                opts.setPendingIntentBackgroundActivityStartMode(
-                        ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
-                smartReplies.pendingIntent.send(context, 0, intent, /* onFinished */null,
-                        /* handler */ null, /* requiredPermission */ null, opts.toBundle())
-            } catch (e: PendingIntent.CanceledException) {
-                Log.w(TAG, "Unable to send smart reply", e)
+                    false, /* modifiedBeforeSending */
+                )
+                entry.setHasSentReply()
+                try {
+                    val intent = createRemoteInputIntent(smartReplies, choice)
+                    val opts = ActivityOptions.makeBasic()
+                    opts.setPendingIntentBackgroundActivityStartMode(
+                        ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+                    )
+                    smartReplies.pendingIntent.send(
+                        context,
+                        0,
+                        intent, /* onFinished */
+                        null,
+                        /* handler */ null, /* requiredPermission */
+                        null,
+                        opts.toBundle(),
+                    )
+                } catch (e: PendingIntent.CanceledException) {
+                    Log.w(TAG, "Unable to send smart reply", e)
+                }
+                smartReplyView.hideSmartSuggestions()
             }
-            smartReplyView.hideSmartSuggestions()
+            false // do not defer
         }
-        false // do not defer
-    }
 
     private fun createRemoteInputIntent(smartReplies: SmartReplies, choice: CharSequence): Intent {
         val results = Bundle()
@@ -516,12 +584,11 @@
 }
 
 /**
- * An OnClickListener wrapper that blocks the underlying OnClickListener for a given amount of
- * time.
+ * An OnClickListener wrapper that blocks the underlying OnClickListener for a given amount of time.
  */
 private class DelayedOnClickListener(
     private val mActualListener: View.OnClickListener,
-    private val mInitDelayMs: Long
+    private val mInitDelayMs: Long,
 ) : View.OnClickListener {
 
     private val mInitTimeMs = SystemClock.elapsedRealtime()
@@ -535,7 +602,7 @@
     }
 
     private fun hasFinishedInitialization(): Boolean =
-            SystemClock.elapsedRealtime() >= mInitTimeMs + mInitDelayMs
+        SystemClock.elapsedRealtime() >= mInitTimeMs + mInitDelayMs
 }
 
 private const val TAG = "SmartReplyViewInflater"
@@ -544,12 +611,12 @@
 // convenience function that swaps parameter order so that lambda can be placed at the end
 private fun KeyguardDismissUtil.executeWhenUnlocked(
     requiresShadeOpen: Boolean,
-    onDismissAction: () -> Boolean
+    onDismissAction: () -> Boolean,
 ) = executeWhenUnlocked(onDismissAction, requiresShadeOpen, false)
 
 // convenience function that swaps parameter order so that lambda can be placed at the end
 private fun ActivityStarter.startPendingIntentDismissingKeyguard(
     intent: PendingIntent,
     associatedView: View?,
-    runnable: () -> Unit
-) = startPendingIntentDismissingKeyguard(intent, runnable::invoke, associatedView)
\ No newline at end of file
+    runnable: () -> Unit,
+) = startPendingIntentDismissingKeyguard(intent, runnable::invoke, associatedView)
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt
index bcf4bad..45fdd21 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt
@@ -63,7 +63,8 @@
 private fun rememberHomeGestureRecognizer(resources: Resources): GestureRecognizer {
     val distance =
         resources.getDimensionPixelSize(R.dimen.touchpad_tutorial_gestures_distance_threshold)
-    return remember(distance) { HomeGestureRecognizer(distance) }
+    val velocity = resources.getDimension(R.dimen.touchpad_home_gesture_velocity_threshold)
+    return remember(distance) { HomeGestureRecognizer(distance, velocity) }
 }
 
 @Composable
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureRecognizer.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureRecognizer.kt
index e10b825..9801626 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureRecognizer.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureRecognizer.kt
@@ -19,9 +19,14 @@
 import android.util.MathUtils
 import android.view.MotionEvent
 import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.InProgress
+import kotlin.math.abs
 
 /** Recognizes touchpad home gesture, that is - using three fingers on touchpad - swiping up. */
-class HomeGestureRecognizer(private val gestureDistanceThresholdPx: Int) : GestureRecognizer {
+class HomeGestureRecognizer(
+    private val gestureDistanceThresholdPx: Int,
+    private val velocityThresholdPxPerMs: Float,
+    private val velocityTracker: VelocityTracker = VerticalVelocityTracker(),
+) : GestureRecognizer {
 
     private val distanceTracker = DistanceTracker()
     private var gestureStateChangedCallback: (GestureState) -> Unit = {}
@@ -37,10 +42,14 @@
     override fun accept(event: MotionEvent) {
         if (!isThreeFingerTouchpadSwipe(event)) return
         val gestureState = distanceTracker.processEvent(event)
+        velocityTracker.accept(event)
         updateGestureState(
             gestureStateChangedCallback,
             gestureState,
-            isFinished = { -it.deltaY >= gestureDistanceThresholdPx },
+            isFinished = {
+                -it.deltaY >= gestureDistanceThresholdPx &&
+                    abs(velocityTracker.calculateVelocity().value) >= velocityThresholdPxPerMs
+            },
             progress = { InProgress(MathUtils.saturate(-it.deltaY / gestureDistanceThresholdPx)) },
         )
     }
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureRecognizer.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureRecognizer.kt
index c478886..5ff583a 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureRecognizer.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureRecognizer.kt
@@ -28,10 +28,10 @@
 class RecentAppsGestureRecognizer(
     private val gestureDistanceThresholdPx: Int,
     private val velocityThresholdPxPerMs: Float,
-    private val distanceTracker: DistanceTracker = DistanceTracker(),
-    private val velocityTracker: VerticalVelocityTracker = VerticalVelocityTracker(),
+    private val velocityTracker: VelocityTracker = VerticalVelocityTracker(),
 ) : GestureRecognizer {
 
+    private val distanceTracker = DistanceTracker()
     private var gestureStateChangedCallback: (GestureState) -> Unit = {}
 
     override fun addGestureStateCallback(callback: (GestureState) -> Unit) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt
index 5c0cc81..39b434ad 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt
@@ -21,20 +21,24 @@
 import android.graphics.PixelFormat
 import android.os.Bundle
 import android.view.MotionEvent
+import android.view.View
 import android.view.ViewGroup
 import android.view.WindowManager
+import com.android.app.tracing.coroutines.coroutineScopeTraced
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.res.R
 import com.android.systemui.volume.Events
+import com.android.systemui.volume.dialog.dagger.VolumeDialogComponent
 import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
-import com.android.systemui.volume.dialog.ui.binder.VolumeDialogViewBinder
 import javax.inject.Inject
+import kotlinx.coroutines.awaitCancellation
 
 class VolumeDialog
 @Inject
 constructor(
     @Application context: Context,
-    private val viewBinder: VolumeDialogViewBinder,
+    private val componentFactory: VolumeDialogComponent.Factory,
     private val visibilityInteractor: VolumeDialogVisibilityInteractor,
 ) : Dialog(context, R.style.Theme_SystemUI_Dialog_Volume) {
 
@@ -64,7 +68,14 @@
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setContentView(R.layout.volume_dialog)
-        viewBinder.bind(this)
+        requireViewById<View>(R.id.volume_dialog_root).repeatWhenAttached {
+            coroutineScopeTraced("[Volume]dialog") {
+                val component = componentFactory.create(this)
+                with(component.volumeDialogViewBinder()) { bind(this@VolumeDialog) }
+
+                awaitCancellation()
+            }
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialogPlugin.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialogPlugin.kt
index b912361..094ec39 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialogPlugin.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialogPlugin.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.volume.dialog
 
+import com.android.app.tracing.coroutines.coroutineScopeTraced
 import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.plugins.VolumeDialog
@@ -23,7 +24,6 @@
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
-import kotlinx.coroutines.coroutineScope
 
 class VolumeDialogPlugin
 @Inject
@@ -38,7 +38,7 @@
     override fun init(windowType: Int, callback: VolumeDialog.Callback?) {
         job =
             applicationCoroutineScope.launch {
-                coroutineScope {
+                coroutineScopeTraced("[Volume]plugin") {
                     pluginComponent =
                         volumeDialogPluginComponentFactory.create(this).also {
                             it.viewModel().launchVolumeDialog()
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt
index fb15795..434f6b5 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
 import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderComponent
+import com.android.systemui.volume.dialog.ui.binder.VolumeDialogViewBinder
 import dagger.BindsInstance
 import dagger.Subcomponent
 import kotlinx.coroutines.CoroutineScope
@@ -32,21 +33,21 @@
 @Subcomponent(modules = [VolumeDialogModule::class])
 interface VolumeDialogComponent {
 
-    /**
-     * Provides a coroutine scope to use inside [VolumeDialogScope].
-     * [com.android.systemui.volume.dialog.VolumeDialogPlugin] manages the lifecycle of this scope.
-     * It's cancelled when the dialog is disposed. This helps to free occupied resources when volume
-     * dialog is not shown.
-     */
-    @VolumeDialog fun coroutineScope(): CoroutineScope
-
-    @VolumeDialogScope fun volumeDialog(): com.android.systemui.volume.dialog.VolumeDialog
+    fun volumeDialogViewBinder(): VolumeDialogViewBinder
 
     fun sliderComponentFactory(): VolumeDialogSliderComponent.Factory
 
     @Subcomponent.Factory
     interface Factory {
 
-        fun create(@BindsInstance @VolumeDialog scope: CoroutineScope): VolumeDialogComponent
+        fun create(
+            /**
+             * Provides a coroutine scope to use inside [VolumeDialogScope].
+             * [com.android.systemui.volume.dialog.VolumeDialogPlugin] manages the lifecycle of this
+             * scope. It's cancelled when the dialog is disposed. This helps to free occupied
+             * resources when volume dialog is not shown.
+             */
+            @BindsInstance @VolumeDialog scope: CoroutineScope
+        ): VolumeDialogComponent
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderTouchesViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderTouchesViewBinder.kt
index 7fd177d..e033624 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderTouchesViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderTouchesViewBinder.kt
@@ -18,9 +18,6 @@
 
 import android.annotation.SuppressLint
 import android.view.View
-import com.android.systemui.lifecycle.WindowLifecycleState
-import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.lifecycle.viewModel
 import com.android.systemui.res.R
 import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope
 import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderTouchesViewModel
@@ -30,22 +27,14 @@
 @VolumeDialogSliderScope
 class VolumeDialogSliderTouchesViewBinder
 @Inject
-constructor(private val viewModelFactory: VolumeDialogSliderTouchesViewModel.Factory) {
+constructor(private val viewModel: VolumeDialogSliderTouchesViewModel) {
 
     @SuppressLint("ClickableViewAccessibility")
     fun bind(view: View) {
         with(view.requireViewById<Slider>(R.id.volume_dialog_slider)) {
-            repeatWhenAttached {
-                viewModel(
-                    traceName = "VolumeDialogSliderTouchesViewBinder",
-                    minWindowLifecycleState = WindowLifecycleState.ATTACHED,
-                    factory = { viewModelFactory.create() },
-                ) { viewModel ->
-                    setOnTouchListener { _, event ->
-                        viewModel.onTouchEvent(event)
-                        false
-                    }
-                }
+            setOnTouchListener { _, event ->
+                viewModel.onTouchEvent(event)
+                false
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt
index 1c231b5..f9334df 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt
@@ -20,9 +20,6 @@
 import android.animation.ObjectAnimator
 import android.view.View
 import android.view.animation.DecelerateInterpolator
-import com.android.systemui.lifecycle.WindowLifecycleState
-import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.lifecycle.viewModel
 import com.android.systemui.res.R
 import com.android.systemui.volume.dialog.shared.model.VolumeDialogStreamModel
 import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope
@@ -33,7 +30,7 @@
 import com.google.android.material.slider.Slider
 import javax.inject.Inject
 import kotlin.math.roundToInt
-import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 
@@ -43,32 +40,20 @@
 class VolumeDialogSliderViewBinder
 @Inject
 constructor(
-    private val viewModelFactory: VolumeDialogSliderViewModel.Factory,
+    private val viewModel: VolumeDialogSliderViewModel,
     private val jankListenerFactory: JankListenerFactory,
 ) {
 
-    fun bind(view: View) {
-        with(view) {
-            val sliderView: Slider =
-                requireViewById<Slider>(R.id.volume_dialog_slider).apply {
-                    labelBehavior = LabelFormatter.LABEL_GONE
-                }
-            repeatWhenAttached {
-                viewModel(
-                    traceName = "VolumeDialogSliderViewBinder",
-                    minWindowLifecycleState = WindowLifecycleState.ATTACHED,
-                    factory = { viewModelFactory.create() },
-                ) { viewModel ->
-                    sliderView.addOnChangeListener { _, value, fromUser ->
-                        viewModel.setStreamVolume(value.roundToInt(), fromUser)
-                    }
-
-                    viewModel.model.onEach { it.bindToSlider(sliderView) }.launchIn(this)
-
-                    awaitCancellation()
-                }
+    fun CoroutineScope.bind(view: View) {
+        val sliderView: Slider =
+            view.requireViewById<Slider>(R.id.volume_dialog_slider).apply {
+                labelBehavior = LabelFormatter.LABEL_GONE
             }
+        sliderView.addOnChangeListener { _, value, fromUser ->
+            viewModel.setStreamVolume(value.roundToInt(), fromUser)
         }
+
+        viewModel.model.onEach { it.bindToSlider(sliderView) }.launchIn(this)
     }
 
     private suspend fun VolumeDialogStreamModel.bindToSlider(slider: Slider) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt
index 1b2b4ff..242845a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt
@@ -21,58 +21,47 @@
 import android.view.ViewGroup
 import androidx.annotation.LayoutRes
 import androidx.compose.ui.util.fastForEachIndexed
-import com.android.systemui.lifecycle.WindowLifecycleState
-import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.lifecycle.viewModel
 import com.android.systemui.res.R
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
 import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderComponent
 import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSlidersViewModel
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 
 @VolumeDialogScope
 class VolumeDialogSlidersViewBinder
 @Inject
-constructor(private val viewModelFactory: VolumeDialogSlidersViewModel.Factory) {
+constructor(private val viewModel: VolumeDialogSlidersViewModel) {
 
-    fun bind(view: View) {
-        with(view) {
-            val floatingSlidersContainer: ViewGroup =
-                requireViewById(R.id.volume_dialog_floating_sliders_container)
-            val mainSliderContainer: View =
-                requireViewById(R.id.volume_dialog_main_slider_container)
-            repeatWhenAttached {
-                viewModel(
-                    traceName = "VolumeDialogSlidersViewBinder",
-                    minWindowLifecycleState = WindowLifecycleState.ATTACHED,
-                    factory = { viewModelFactory.create() },
-                ) { viewModel ->
-                    viewModel.sliders
-                        .onEach { uiModel ->
-                            uiModel.sliderComponent.bindSlider(mainSliderContainer)
+    fun CoroutineScope.bind(view: View) {
+        val floatingSlidersContainer: ViewGroup =
+            view.requireViewById(R.id.volume_dialog_floating_sliders_container)
+        val mainSliderContainer: View =
+            view.requireViewById(R.id.volume_dialog_main_slider_container)
+        viewModel.sliders
+            .onEach { uiModel ->
+                bindSlider(uiModel.sliderComponent, mainSliderContainer)
 
-                            val floatingSliderViewBinders = uiModel.floatingSliderComponent
-                            floatingSlidersContainer.ensureChildCount(
-                                viewLayoutId = R.layout.volume_dialog_slider_floating,
-                                count = floatingSliderViewBinders.size,
-                            )
-                            floatingSliderViewBinders.fastForEachIndexed { index, sliderComponent ->
-                                sliderComponent.bindSlider(
-                                    floatingSlidersContainer.getChildAt(index)
-                                )
-                            }
-                        }
-                        .launchIn(this)
+                val floatingSliderViewBinders = uiModel.floatingSliderComponent
+                floatingSlidersContainer.ensureChildCount(
+                    viewLayoutId = R.layout.volume_dialog_slider_floating,
+                    count = floatingSliderViewBinders.size,
+                )
+                floatingSliderViewBinders.fastForEachIndexed { index, sliderComponent ->
+                    bindSlider(sliderComponent, floatingSlidersContainer.getChildAt(index))
                 }
             }
-        }
+            .launchIn(this)
     }
 
-    private fun VolumeDialogSliderComponent.bindSlider(sliderContainer: View) {
-        sliderViewBinder().bind(sliderContainer)
-        sliderTouchesViewBinder().bind(sliderContainer)
+    private fun CoroutineScope.bindSlider(
+        component: VolumeDialogSliderComponent,
+        sliderContainer: View,
+    ) {
+        with(component.sliderViewBinder()) { bind(sliderContainer) }
+        with(component.sliderTouchesViewBinder()) { bind(sliderContainer) }
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderTouchesViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderTouchesViewModel.kt
index 144c75d..9126f45 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderTouchesViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderTouchesViewModel.kt
@@ -17,20 +17,16 @@
 package com.android.systemui.volume.dialog.sliders.ui.viewmodel
 
 import android.view.MotionEvent
+import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope
 import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSliderInputEventsInteractor
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
+import javax.inject.Inject
 
+@VolumeDialogSliderScope
 class VolumeDialogSliderTouchesViewModel
-@AssistedInject
+@Inject
 constructor(private val interactor: VolumeDialogSliderInputEventsInteractor) {
 
     fun onTouchEvent(event: MotionEvent) {
         interactor.onTouchEvent(event)
     }
-
-    @AssistedFactory
-    interface Factory {
-        fun create(): VolumeDialogSliderTouchesViewModel
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt
index cf04d45..6dd5b63 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt
@@ -21,9 +21,9 @@
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
 import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
 import com.android.systemui.volume.dialog.shared.model.VolumeDialogStreamModel
+import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope
 import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSliderInteractor
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
+import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
@@ -49,8 +49,9 @@
 private const val VOLUME_UPDATE_GRACE_PERIOD = 1000
 
 @OptIn(ExperimentalCoroutinesApi::class)
+@VolumeDialogSliderScope
 class VolumeDialogSliderViewModel
-@AssistedInject
+@Inject
 constructor(
     private val interactor: VolumeDialogSliderInteractor,
     private val visibilityInteractor: VolumeDialogVisibilityInteractor,
@@ -90,10 +91,4 @@
     private fun getTimestampMillis(): Long = systemClock.uptimeMillis()
 
     private data class VolumeUpdate(val newVolumeLevel: Int, val timestampMillis: Long)
-
-    @AssistedFactory
-    interface Factory {
-
-        fun create(): VolumeDialogSliderViewModel
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModel.kt
index d197223..d8e6aec 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModel.kt
@@ -17,10 +17,10 @@
 package com.android.systemui.volume.dialog.sliders.ui.viewmodel
 
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
 import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderComponent
 import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSlidersInteractor
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
+import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
@@ -28,8 +28,9 @@
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
 
+@VolumeDialogScope
 class VolumeDialogSlidersViewModel
-@AssistedInject
+@Inject
 constructor(
     @VolumeDialog coroutineScope: CoroutineScope,
     private val slidersInteractor: VolumeDialogSlidersInteractor,
@@ -47,12 +48,6 @@
             }
             .stateIn(coroutineScope, SharingStarted.Eagerly, null)
             .filterNotNull()
-
-    @AssistedFactory
-    interface Factory {
-
-        fun create(): VolumeDialogSlidersViewModel
-    }
 }
 
 /** Models slider ui */
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
index f6c1743..a3166a9 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
@@ -25,9 +25,6 @@
 import android.view.ViewTreeObserver.InternalInsetsInfo
 import androidx.constraintlayout.motion.widget.MotionLayout
 import com.android.internal.view.RotationPolicy
-import com.android.systemui.lifecycle.WindowLifecycleState
-import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.lifecycle.viewModel
 import com.android.systemui.res.R
 import com.android.systemui.util.children
 import com.android.systemui.volume.SystemUIInterpolators
@@ -44,7 +41,6 @@
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.awaitCancellation
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.flow.launchIn
@@ -61,7 +57,7 @@
 @Inject
 constructor(
     private val volumeResources: VolumeDialogResources,
-    private val dialogViewModelFactory: VolumeDialogViewModel.Factory,
+    private val viewModel: VolumeDialogViewModel,
     private val jankListenerFactory: JankListenerFactory,
     private val tracer: VolumeTracer,
     private val volumeDialogRingerViewBinder: VolumeDialogRingerViewBinder,
@@ -69,35 +65,27 @@
     private val settingsButtonViewBinder: VolumeDialogSettingsButtonViewBinder,
 ) {
 
-    fun bind(dialog: Dialog) {
+    fun CoroutineScope.bind(dialog: Dialog) {
         // Root view of the Volume Dialog.
         val root: MotionLayout = dialog.requireViewById(R.id.volume_dialog_root)
         root.alpha = 0f
-        root.repeatWhenAttached {
-            root.viewModel(
-                traceName = "VolumeDialogViewBinder",
-                minWindowLifecycleState = WindowLifecycleState.ATTACHED,
-                factory = { dialogViewModelFactory.create() },
-            ) { viewModel ->
-                animateVisibility(root, dialog, viewModel.dialogVisibilityModel)
 
-                viewModel.dialogTitle.onEach { dialog.window?.setTitle(it) }.launchIn(this)
-                viewModel.motionState
-                    .scan(0) { acc, motionState ->
-                        // don't animate the initial state
-                        root.transitionToState(motionState, animate = acc != 0)
-                        acc + 1
-                    }
-                    .launchIn(this)
+        animateVisibility(root, dialog, viewModel.dialogVisibilityModel)
 
-                launch { root.viewTreeObserver.computeInternalInsetsListener(root) }
-
-                awaitCancellation()
+        viewModel.dialogTitle.onEach { dialog.window?.setTitle(it) }.launchIn(this)
+        viewModel.motionState
+            .scan(0) { acc, motionState ->
+                // don't animate the initial state
+                root.transitionToState(motionState, animate = acc != 0)
+                acc + 1
             }
-        }
-        volumeDialogRingerViewBinder.bind(root)
-        slidersViewBinder.bind(root)
-        settingsButtonViewBinder.bind(root)
+            .launchIn(this)
+
+        launch { root.viewTreeObserver.computeInternalInsetsListener(root) }
+
+        with(volumeDialogRingerViewBinder) { bind(root) }
+        with(slidersViewBinder) { bind(root) }
+        with(settingsButtonViewBinder) { bind(root) }
     }
 
     private fun CoroutineScope.animateVisibility(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt
index e858cfe..ff525f46 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt
@@ -17,14 +17,14 @@
 package com.android.systemui.volume.dialog.ui.viewmodel
 
 import com.android.systemui.volume.Events
-import com.android.systemui.volume.dialog.dagger.VolumeDialogComponent
+import com.android.systemui.volume.dialog.VolumeDialog
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPluginScope
 import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
 import com.android.systemui.volume.dialog.shared.VolumeDialogLogger
 import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
 import javax.inject.Inject
+import javax.inject.Provider
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.cancel
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.mapLatest
@@ -34,8 +34,8 @@
 class VolumeDialogPluginViewModel
 @Inject
 constructor(
-    private val componentFactory: VolumeDialogComponent.Factory,
     private val dialogVisibilityInteractor: VolumeDialogVisibilityInteractor,
+    private val volumeDialogProvider: Provider<VolumeDialog>,
     private val logger: VolumeDialogLogger,
 ) {
 
@@ -45,7 +45,7 @@
                 .mapLatest { visibilityModel ->
                     with(visibilityModel) {
                         if (this is VolumeDialogVisibilityModel.Visible) {
-                            showDialog(componentFactory)
+                            showDialog()
                             Events.writeEvent(Events.EVENT_SHOW_DIALOG, reason, keyguardLocked)
                             logger.onShow(reason)
                         }
@@ -59,16 +59,14 @@
         }
     }
 
-    private suspend fun showDialog(componentFactory: VolumeDialogComponent.Factory): Unit =
-        coroutineScope {
-            val volumeDialogComponent: VolumeDialogComponent = componentFactory.create(this)
-            val dialog =
-                volumeDialogComponent.volumeDialog().apply {
-                    setOnDismissListener {
-                        volumeDialogComponent.coroutineScope().cancel()
-                        dialogVisibilityInteractor.dismissDialog(Events.DISMISS_REASON_UNKNOWN)
-                    }
+    private fun showDialog() {
+        volumeDialogProvider
+            .get()
+            .apply {
+                setOnDismissListener {
+                    dialogVisibilityInteractor.dismissDialog(Events.DISMISS_REASON_UNKNOWN)
                 }
-            dialog.show()
-        }
+            }
+            .show()
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt
index 0352799..7a6ede4 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.statusbar.policy.DevicePostureController
 import com.android.systemui.statusbar.policy.devicePosture
 import com.android.systemui.statusbar.policy.onConfigChanged
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
 import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogStateInteractor
 import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
 import com.android.systemui.volume.dialog.shared.model.VolumeDialogStateModel
@@ -30,9 +31,7 @@
 import com.android.systemui.volume.dialog.shared.model.streamLabel
 import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSlidersInteractor
 import com.android.systemui.volume.dialog.sliders.domain.model.VolumeDialogSliderType
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
-import kotlinx.coroutines.ExperimentalCoroutinesApi
+import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.filterNotNull
@@ -40,9 +39,9 @@
 import kotlinx.coroutines.flow.onStart
 
 /** Provides a state for the Volume Dialog. */
-@OptIn(ExperimentalCoroutinesApi::class)
+@VolumeDialogScope
 class VolumeDialogViewModel
-@AssistedInject
+@Inject
 constructor(
     private val context: Context,
     dialogVisibilityInteractor: VolumeDialogVisibilityInteractor,
@@ -84,9 +83,4 @@
         val isHalfOpen = devicePosture == DevicePostureController.DEVICE_POSTURE_HALF_OPENED
         return isLandscape && isHalfOpen
     }
-
-    @AssistedFactory
-    interface Factory {
-        fun create(): VolumeDialogViewModel
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
index bf13ceb..4bc5f23 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
@@ -45,6 +45,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.provider.Settings;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
@@ -56,6 +58,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.logging.CarrierTextManagerLogger;
+import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.kosmos.KosmosJavaAdapter;
@@ -200,6 +203,7 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
     public void testAirplaneMode() {
         Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
         reset(mCarrierTextCallback);
@@ -220,8 +224,32 @@
         assertEquals(AIRPLANE_MODE_TEXT, captor.getValue().carrierText);
     }
 
+    @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void testAirplaneMode_flagEnabled() {
+        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(0)).thenReturn(
+                TelephonyManager.SIM_STATE_READY);
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        mCarrierTextManager.updateCarrierText();
+
+        ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextManager.CarrierTextCallbackInfo.class);
+
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+        assertEquals(AIRPLANE_MODE_TEXT, captor.getValue().carrierText);
+    }
+
     /** regression test for b/281706473, caused by sending NULL plmn / spn to the logger */
     @Test
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
     public void testAirplaneMode_noSim_nullPlmn_nullSpn_doesNotCrash() {
         // GIVEN - sticy broadcast that returns a null PLMN and null SPN
         Intent stickyIntent = new Intent(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED);
@@ -263,7 +291,52 @@
         // No assert, this test should not crash
     }
 
+    /** regression test for b/281706473, caused by sending NULL plmn / spn to the logger */
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void testAirplaneMode_noSim_nullPlmn_nullSpn_doesNotCrash_flagEnabled() {
+        // GIVEN - sticy broadcast that returns a null PLMN and null SPN
+        Intent stickyIntent = new Intent(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED);
+        stickyIntent.putExtra(TelephonyManager.EXTRA_SHOW_PLMN, true);
+        stickyIntent.removeExtra(TelephonyManager.EXTRA_PLMN);
+        stickyIntent.putExtra(TelephonyManager.EXTRA_SHOW_SPN, true);
+        stickyIntent.removeExtra(TelephonyManager.EXTRA_SPN);
+
+        mCarrierTextManager = new CarrierTextManager.Builder(
+                getContextSpyForStickyBroadcast(stickyIntent),
+                mContext.getResources(),
+                mWifiRepository,
+                mSatelliteViewModel,
+                mJavaAdapter,
+                mTelephonyManager,
+                mTelephonyListenerManager,
+                mWakefulnessLifecycle,
+                mMainExecutor,
+                mBgExecutor,
+                mKeyguardUpdateMonitor,
+                mLogger
+        )
+                .setShowAirplaneMode(true)
+                .setShowMissingSim(true)
+                .build();
+
+        // GIVEN - airplane mode is off (causing CTM to fetch the sticky broadcast)
+        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(0))
+                .thenReturn(TelephonyManager.SIM_STATE_NOT_READY);
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        // WHEN CTM fetches the broadcast and attempts to log the result, no crash results
+        mCarrierTextManager.updateCarrierText();
+
+        // No assert, this test should not crash
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
     public void testCardIOError() {
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
@@ -299,6 +372,44 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void testCardIOError_flagEnabled() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(0)).thenReturn(
+                TelephonyManager.SIM_STATE_READY);
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(1)).thenReturn(
+                TelephonyManager.SIM_STATE_CARD_IO_ERROR);
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        mCarrierTextManager.mCallback.onSimStateChanged(3, 1,
+                TelephonyManager.SIM_STATE_CARD_IO_ERROR);
+
+        ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextManager.CarrierTextCallbackInfo.class);
+
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+        assertEquals("TEST_CARRIER" + SEPARATOR + INVALID_CARD_TEXT, captor.getValue().carrierText);
+        // There's only one subscription in the list
+        assertEquals(1, captor.getValue().listOfCarriers.length);
+        assertEquals(TEST_CARRIER, captor.getValue().listOfCarriers[0]);
+
+        // Now it becomes single SIM active mode.
+        reset(mCarrierTextCallback);
+        when(mTelephonyManager.getActiveModemCount()).thenReturn(1);
+        // Update carrier text. It should ignore error state of subId 3 in inactive slotId.
+        mCarrierTextManager.updateCarrierText();
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+        assertEquals("TEST_CARRIER", captor.getValue().carrierText);
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
     public void testWrongSlots() {
         reset(mCarrierTextCallback);
         when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(
@@ -313,6 +424,22 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void testWrongSlots_flagEnabled() {
+        reset(mCarrierTextCallback);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(
+                new ArrayList<>());
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(anyInt())).thenReturn(
+                TelephonyManager.SIM_STATE_CARD_IO_ERROR);
+        // This should not produce an out of bounds error, even though there are no subscriptions
+        mCarrierTextManager.mCallback.onSimStateChanged(0, -3,
+                TelephonyManager.SIM_STATE_CARD_IO_ERROR);
+        mCarrierTextManager.mCallback.onSimStateChanged(0, 3, TelephonyManager.SIM_STATE_READY);
+        verify(mCarrierTextCallback, never()).updateCarrierInfo(any());
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
     public void testMoreSlotsThanSubs() {
         reset(mCarrierTextCallback);
         when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(
@@ -335,6 +462,29 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void testMoreSlotsThanSubs_flagEnabled() {
+        reset(mCarrierTextCallback);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(
+                new ArrayList<>());
+
+        // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
+        // same answer as KeyguardUpdateMonitor. Remove when this is addressed
+        when(mSubscriptionManager.getCompleteActiveSubscriptionInfoList()).thenReturn(
+                new ArrayList<>());
+
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(anyInt())).thenReturn(
+                TelephonyManager.SIM_STATE_CARD_IO_ERROR);
+        // This should not produce an out of bounds error, even though there are no subscriptions
+        mCarrierTextManager.mCallback.onSimStateChanged(0, 1,
+                TelephonyManager.SIM_STATE_CARD_IO_ERROR);
+
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+        verify(mCarrierTextCallback).updateCarrierInfo(
+                any(CarrierTextManager.CarrierTextCallbackInfo.class));
+    }
+
+    @Test
     public void testCallback() {
         reset(mCarrierTextCallback);
         mCarrierTextManager.postToCallback(mCarrierTextCallbackInfo);
@@ -360,6 +510,7 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
     public void testCreateInfo_OneValidSubscription() {
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
@@ -385,6 +536,33 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void testCreateInfo_OneValidSubscription_flagEnabled() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(anyInt())).thenReturn(
+                TelephonyManager.SIM_STATE_READY);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
+
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextManager.CarrierTextCallbackInfo.class);
+
+        mCarrierTextManager.updateCarrierText();
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+
+        CarrierTextManager.CarrierTextCallbackInfo info = captor.getValue();
+        assertEquals(1, info.listOfCarriers.length);
+        assertEquals(TEST_CARRIER, info.listOfCarriers[0]);
+        assertEquals(1, info.subscriptionIds.length);
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
     public void testCreateInfo_OneValidSubscriptionWithRoaming() {
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
@@ -410,6 +588,33 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void testCreateInfo_OneValidSubscriptionWithRoaming_flagEnabled() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION_ROAMING);
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(anyInt())).thenReturn(
+                TelephonyManager.SIM_STATE_READY);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
+
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextManager.CarrierTextCallbackInfo.class);
+
+        mCarrierTextManager.updateCarrierText();
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+
+        CarrierTextManager.CarrierTextCallbackInfo info = captor.getValue();
+        assertEquals(1, info.listOfCarriers.length);
+        assertTrue(info.listOfCarriers[0].toString().contains(TEST_CARRIER));
+        assertEquals(1, info.subscriptionIds.length);
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
     public void testCarrierText_noTextOnReadySimWhenNull() {
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
@@ -434,6 +639,32 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void testCarrierText_noTextOnReadySimWhenNull_flagEnabled() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION_NULL);
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(anyInt())).thenReturn(
+                TelephonyManager.SIM_STATE_READY);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
+
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextManager.CarrierTextCallbackInfo.class);
+
+        mCarrierTextManager.updateCarrierText();
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+
+        assertTrue("Carrier text should be empty, instead it's " + captor.getValue().carrierText,
+                TextUtils.isEmpty(captor.getValue().carrierText));
+        assertFalse("No SIM should be available", captor.getValue().anySimReady);
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
     public void testCarrierText_noTextOnReadySimWhenNull_airplaneMode_wifiOn() {
         Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
         reset(mCarrierTextCallback);
@@ -472,6 +703,46 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void testCarrierText_noTextOnReadySimWhenNull_airplaneMode_wifiOn_flagEnabled() {
+        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION_NULL);
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(anyInt())).thenReturn(
+                TelephonyManager.SIM_STATE_READY);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
+
+        assertFalse(mWifiRepository.isWifiConnectedWithValidSsid());
+        mWifiRepository.setWifiNetwork(
+                WifiNetworkModel.Active.Companion.of(
+                        /* isValidated= */ false,
+                        /* level= */ 0,
+                        /* ssid= */ "",
+                        /* hotspotDeviceType= */ WifiNetworkModel.HotspotDeviceType.NONE));
+        assertTrue(mWifiRepository.isWifiConnectedWithValidSsid());
+
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+        ServiceState ss = mock(ServiceState.class);
+        when(ss.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+        mKeyguardUpdateMonitor.mServiceStates.put(TEST_SUBSCRIPTION_NULL.getSubscriptionId(), ss);
+
+        ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextManager.CarrierTextCallbackInfo.class);
+
+        mCarrierTextManager.updateCarrierText();
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+
+        assertFalse("No SIM should be available", captor.getValue().anySimReady);
+        // There's no airplane mode if at least one SIM is State.READY and there's wifi
+        assertFalse("Device should not be in airplane mode", captor.getValue().airplaneMode);
+        assertNotEquals(AIRPLANE_MODE_TEXT, captor.getValue().carrierText);
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
     public void carrierText_satelliteTextNull_isSatelliteFalse_textNotUsed() {
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
@@ -497,6 +768,33 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void carrierText_satelliteTextNull_isSatelliteFalse_textNotUsed_flagEnabled() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(anyInt())).thenReturn(
+                TelephonyManager.SIM_STATE_READY);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        // WHEN the satellite text is null
+        mSatelliteViewModel.getCarrierText().setValue(null);
+        mTestScope.getTestScheduler().runCurrent();
+
+        ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextManager.CarrierTextCallbackInfo.class);
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+
+        // THEN satellite mode is false and the default subscription carrier text is used
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+        assertThat(captor.getValue().isInSatelliteMode).isFalse();
+        assertThat(captor.getValue().carrierText).isEqualTo(TEST_CARRIER);
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
     public void carrierText_hasSatelliteText_isSatelliteTrue_textUsed() {
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
@@ -522,6 +820,33 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void carrierText_hasSatelliteText_isSatelliteTrue_textUsed_flagEnabled() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(anyInt())).thenReturn(
+                TelephonyManager.SIM_STATE_READY);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        // WHEN the satellite text is non-null
+        mSatelliteViewModel.getCarrierText().setValue("Satellite Test Text");
+        mTestScope.getTestScheduler().runCurrent();
+
+        ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextManager.CarrierTextCallbackInfo.class);
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+
+        // THEN satellite mode is true and the satellite text is used
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+        assertThat(captor.getValue().isInSatelliteMode).isTrue();
+        assertThat(captor.getValue().carrierText).isEqualTo("Satellite Test Text");
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
     public void carrierText_satelliteTextUpdates_autoTriggersCallback() {
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
@@ -559,6 +884,45 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void carrierText_satelliteTextUpdates_autoTriggersCallback_flagEnabled() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(anyInt())).thenReturn(
+                TelephonyManager.SIM_STATE_READY);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        // WHEN the satellite text is set
+        mSatelliteViewModel.getCarrierText().setValue("Test satellite text");
+        mTestScope.getTestScheduler().runCurrent();
+
+        // THEN we should automatically re-trigger #updateCarrierText and get callback info
+        ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextManager.CarrierTextCallbackInfo.class);
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+        // AND use the satellite text as the carrier text
+        assertThat(captor.getValue().isInSatelliteMode).isTrue();
+        assertThat(captor.getValue().carrierText).isEqualTo("Test satellite text");
+
+        // WHEN the satellite text is reset to null
+        reset(mCarrierTextCallback);
+        mSatelliteViewModel.getCarrierText().setValue(null);
+        mTestScope.getTestScheduler().runCurrent();
+
+        // THEN we should automatically re-trigger #updateCarrierText and get callback info
+        // that doesn't include the satellite info
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+        assertThat(captor.getValue().isInSatelliteMode).isFalse();
+        assertThat(captor.getValue().carrierText).isEqualTo(TEST_CARRIER);
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
     public void carrierText_updatedWhileNotListening_getsNewValueWhenListening() {
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
@@ -602,6 +966,50 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void carrierText_updatedWhileNotListening_getsNewValueWhenListening_flagEnabled() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(anyInt())).thenReturn(
+                TelephonyManager.SIM_STATE_READY);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        mSatelliteViewModel.getCarrierText().setValue("Old satellite text");
+        mTestScope.getTestScheduler().runCurrent();
+
+        ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextManager.CarrierTextCallbackInfo.class);
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+        assertThat(captor.getValue().carrierText).isEqualTo("Old satellite text");
+
+        // WHEN we stop listening
+        reset(mCarrierTextCallback);
+        mCarrierTextManager.setListening(null);
+
+        // AND the satellite text updates
+        mSatelliteViewModel.getCarrierText().setValue("New satellite text");
+
+        // THEN we don't get new callback info because we aren't listening
+        verify(mCarrierTextCallback, never()).updateCarrierInfo(any());
+
+        // WHEN we start listening again
+        reset(mCarrierTextCallback);
+        mCarrierTextManager.setListening(mCarrierTextCallback);
+
+        // THEN we should automatically re-trigger #updateCarrierText and get callback info
+        // that includes the new satellite state and text
+        mTestScope.getTestScheduler().runCurrent();
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+        assertThat(captor.getValue().isInSatelliteMode).isTrue();
+        assertThat(captor.getValue().carrierText).isEqualTo("New satellite text");
+    }
+
+    @Test
     public void testCreateInfo_noSubscriptions() {
         reset(mCarrierTextCallback);
         when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(
@@ -622,6 +1030,7 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
     public void testCarrierText_oneValidSubscription() {
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
@@ -644,6 +1053,30 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void testCarrierText_oneValidSubscription_flagEnabled() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(anyInt())).thenReturn(
+                TelephonyManager.SIM_STATE_READY);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
+
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextManager.CarrierTextCallbackInfo.class);
+
+        mCarrierTextManager.updateCarrierText();
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+
+        assertThat(captor.getValue().carrierText).isEqualTo(TEST_CARRIER);
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
     public void testCarrierText_twoValidSubscriptions() {
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
@@ -668,6 +1101,32 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void testCarrierText_twoValidSubscriptions_flagEnabled() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(anyInt())).thenReturn(
+                TelephonyManager.SIM_STATE_READY);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
+
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextManager.CarrierTextCallbackInfo.class);
+
+        mCarrierTextManager.updateCarrierText();
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+
+        assertEquals(TEST_CARRIER + SEPARATOR + TEST_CARRIER,
+                captor.getValue().carrierText);
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
     public void testCarrierText_oneDisabledSub() {
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
@@ -693,6 +1152,33 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void testCarrierText_oneDisabledSub_flagEnabled() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(anyInt()))
+                .thenReturn(TelephonyManager.SIM_STATE_READY)
+                .thenReturn(TelephonyManager.SIM_STATE_NOT_READY);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
+
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextManager.CarrierTextCallbackInfo.class);
+
+        mCarrierTextManager.updateCarrierText();
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+
+        assertEquals(TEST_CARRIER,
+                captor.getValue().carrierText);
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
     public void testCarrierText_firstDisabledSub() {
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
@@ -718,6 +1204,33 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void testCarrierText_firstDisabledSub_flagEnabled() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(anyInt()))
+                .thenReturn(TelephonyManager.SIM_STATE_NOT_READY)
+                .thenReturn(TelephonyManager.SIM_STATE_READY);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
+
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextManager.CarrierTextCallbackInfo.class);
+
+        mCarrierTextManager.updateCarrierText();
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+
+        assertEquals(TEST_CARRIER,
+                captor.getValue().carrierText);
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
     public void testCarrierText_threeSubsMiddleDisabled() {
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
@@ -744,6 +1257,33 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void testCarrierText_threeSubsMiddleDisabled_flagEnabled() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        list.add(TEST_SUBSCRIPTION);
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getSimStateForSlotId(anyInt()))
+                .thenReturn(TelephonyManager.SIM_STATE_READY)
+                .thenReturn(TelephonyManager.SIM_STATE_NOT_READY)
+                .thenReturn(TelephonyManager.SIM_STATE_READY);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextManager.CarrierTextCallbackInfo.class);
+
+        mCarrierTextManager.updateCarrierText();
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+
+        assertEquals(TEST_CARRIER + SEPARATOR + TEST_CARRIER,
+                captor.getValue().carrierText);
+    }
+
+    @Test
     public void testGetStatusForIccState() {
         when(mKeyguardUpdateMonitor.isDeviceProvisioned()).thenReturn(false);
         assertEquals(CarrierTextManager.StatusMode.SimMissingLocked,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index a39ca5d..839a2bd 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -103,6 +103,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.FlagsParameterization;
 import android.service.dreams.IDreamManager;
@@ -200,8 +201,9 @@
     private static final String TEST_CARRIER_2 = "TEST_CARRIER_2";
     private static final int TEST_CARRIER_ID = 1;
     private static final String TEST_GROUP_UUID = "59b5c870-fc4c-47a4-a99e-9db826b48b24";
-    private static final SubscriptionInfo TEST_SUBSCRIPTION = new SubscriptionInfo(1, "", 0,
-            TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_CARRIER_ID, 0xFFFFFF, "",
+    private static final int TEST_SLOT_ID = 3;
+    private static final SubscriptionInfo TEST_SUBSCRIPTION = new SubscriptionInfo(1, "",
+            TEST_SLOT_ID, TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_CARRIER_ID, 0xFFFFFF, "",
             DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, TEST_GROUP_UUID,
             TEST_CARRIER_ID, 0);
     private static final SubscriptionInfo TEST_SUBSCRIPTION_2 = new SubscriptionInfo(2, "", 0,
@@ -483,7 +485,8 @@
     }
 
     @Test
-    public void testSimStateInitialized() {
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void testSimStateInitialized_flagDisabled() {
         cleanupKeyguardUpdateMonitor();
         final int subId = 3;
         final int state = TelephonyManager.SIM_STATE_ABSENT;
@@ -500,6 +503,24 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void testSimStateInitialized_flagEnabled() {
+        cleanupKeyguardUpdateMonitor();
+        final int state = TelephonyManager.SIM_STATE_ABSENT;
+        final int slotId = 0;
+        final int subId = 3;
+        when(mTelephonyManager.getActiveModemCount()).thenReturn(1);
+        when(mTelephonyManager.getSimState(anyInt())).thenReturn(state);
+        when(mSubscriptionManager.getSubscriptionIds(anyInt())).thenReturn(new int[]{subId});
+
+        KeyguardUpdateMonitor testKUM = new TestableKeyguardUpdateMonitor(mContext);
+
+        mTestableLooper.processAllMessages();
+
+        assertThat(testKUM.getSimStateForSlotId(slotId)).isEqualTo(state);
+    }
+
+    @Test
     public void testIgnoresSimStateCallback_rebroadcast() {
         Intent intent = defaultSimStateChangedIntent();
 
@@ -1240,7 +1261,8 @@
     }
 
     @Test
-    public void testActiveSubscriptionBecomesInactive() {
+    @DisableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void testActiveSubscriptionBecomesInactive_flagDisabled() {
         List<SubscriptionInfo> list = new ArrayList<>();
         list.add(TEST_SUBSCRIPTION);
         when(mSubscriptionManager.getCompleteActiveSubscriptionInfoList()).thenReturn(list);
@@ -1263,6 +1285,28 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_SIM_PIN_USE_SLOT_ID)
+    public void testActiveSubscriptionBecomesInactive_flagEnabled() {
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        when(mSubscriptionManager.getCompleteActiveSubscriptionInfoList()).thenReturn(list);
+        mKeyguardUpdateMonitor.mPhoneStateListener.onActiveDataSubscriptionIdChanged(
+                TEST_SUBSCRIPTION.getSubscriptionId());
+        mTestableLooper.processAllMessages();
+        assertThat(mKeyguardUpdateMonitor.mSimDatasBySlotId.get(TEST_SLOT_ID))
+                .isNotNull();
+
+        when(mSubscriptionManager.getCompleteActiveSubscriptionInfoList())
+                .thenReturn(new ArrayList<>());
+        mKeyguardUpdateMonitor.mPhoneStateListener.onActiveDataSubscriptionIdChanged(
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        mTestableLooper.processAllMessages();
+
+        assertThat(mKeyguardUpdateMonitor.mSimDatasBySlotId.get(TEST_SLOT_ID))
+                .isNull();
+    }
+
+    @Test
     public void testActiveSubscriptionList_filtersProvisioningNetworks() {
         List<SubscriptionInfo> list = new ArrayList<>();
         list.add(TEST_SUBSCRIPTION_PROVISIONING);
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 fa88f62..ad5f960 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
@@ -930,6 +930,10 @@
     }
 
     private void advanceTimeBy(long timeDelta) {
+        if (timeDelta == mWaitAnimationDuration) {
+            mAnimatorTestRule.advanceAnimationDuration(timeDelta);
+            return;
+        }
         mAnimatorTestRule.advanceTimeBy(timeDelta);
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
similarity index 96%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index f41d5c8..8552e48 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -63,8 +63,6 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.platform.test.annotations.DisableFlags;
-import android.platform.test.annotations.EnableFlags;
 import android.provider.Settings;
 import android.testing.TestableLooper;
 import android.testing.TestableResources;
@@ -90,7 +88,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.LargeTest;
 
-import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.animation.AnimatorTestRule;
 import com.android.systemui.kosmos.KosmosJavaAdapter;
@@ -612,46 +609,6 @@
                 .isEqualTo(expectedRatio);
     }
 
-    @DisableFlags(Flags.FLAG_SAVE_AND_RESTORE_MAGNIFICATION_SETTINGS_BUTTONS)
-    @Test
-    public void onScreenSizeAndDensityChanged_enabled_restoreSavedMagnifierWindow() {
-        int newSmallestScreenWidthDp =
-                mContext.getResources().getConfiguration().smallestScreenWidthDp * 2;
-        int windowFrameSize = mResources.getDimensionPixelSize(
-                com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
-        Size preferredWindowSize = new Size(windowFrameSize, windowFrameSize);
-        mSharedPreferences
-                .edit()
-                .putString(String.valueOf(newSmallestScreenWidthDp),
-                        preferredWindowSize.toString())
-                .commit();
-        mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
-                    Float.NaN);
-        });
-
-        // Screen density and size change
-        mContext.getResources().getConfiguration().smallestScreenWidthDp = newSmallestScreenWidthDp;
-        final Rect testWindowBounds = new Rect(
-                mWindowManager.getCurrentWindowMetrics().getBounds());
-        testWindowBounds.set(testWindowBounds.left, testWindowBounds.top,
-                testWindowBounds.right + 100, testWindowBounds.bottom + 100);
-        mWindowManager.setWindowBounds(testWindowBounds);
-        mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_SCREEN_SIZE);
-        });
-
-        // wait for rect update
-        waitForIdleSync();
-        ViewGroup.LayoutParams params = mSurfaceControlViewHost.getView().getLayoutParams();
-        final int mirrorSurfaceMargin = mResources.getDimensionPixelSize(
-                R.dimen.magnification_mirror_surface_margin);
-        // The width and height of the view include the magnification frame and the margins.
-        assertThat(params.width).isEqualTo(windowFrameSize + 2 * mirrorSurfaceMargin);
-        assertThat(params.height).isEqualTo(windowFrameSize + 2 * mirrorSurfaceMargin);
-    }
-
-    @EnableFlags(Flags.FLAG_SAVE_AND_RESTORE_MAGNIFICATION_SETTINGS_BUTTONS)
     @Test
     public void onScreenSizeAndDensityChanged_enabled_restoreSavedMagnifierIndexAndWindow() {
         int newSmallestScreenWidthDp =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
index 7c0c5c2..4553f98 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
@@ -59,6 +59,7 @@
 import android.widget.Button;
 import android.widget.CompoundButton;
 import android.widget.LinearLayout;
+import android.widget.SeekBar;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -81,6 +82,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
@@ -544,9 +546,10 @@
         OnSeekBarWithIconButtonsChangeListener onChangeListener =
                 mZoomSeekbar.getOnSeekBarWithIconButtonsChangeListener();
 
-        mZoomSeekbar.setProgress(30);
+        SeekBar mockSeekBar = Mockito.mock(SeekBar.class);
+        when(mockSeekBar.getProgress()).thenReturn(30);
         onChangeListener.onUserInteractionFinalized(
-                mZoomSeekbar.getSeekbar(),
+                mockSeekBar,
                 OnSeekBarWithIconButtonsChangeListener.ControlUnitType.SLIDER);
 
         // should trigger callback to update magnifier scale and persist the scale
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
index 425aad2..4aaa82e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
@@ -404,7 +404,7 @@
     @Test
     fun creatingRunnerWithLazyInitializationThrows_whenTheFlagsAreDisabled() {
         assertThrows(IllegalStateException::class.java) {
-            activityTransitionAnimator.createRunner(controller, initializeLazily = true)
+            activityTransitionAnimator.createRunner(controller, longLived = true)
         }
     }
 
@@ -414,7 +414,7 @@
     )
     @Test
     fun runnerCreatesDelegateLazily_whenPostingTimeouts() {
-        val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = true)
+        val runner = activityTransitionAnimator.createRunner(controller, longLived = true)
         assertNull(runner.delegate)
         runner.postTimeouts()
         assertNotNull(runner.delegate)
@@ -426,7 +426,7 @@
     )
     @Test
     fun runnerCreatesDelegateLazily_onAnimationStart() {
-        val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = true)
+        val runner = activityTransitionAnimator.createRunner(controller, longLived = true)
         assertNull(runner.delegate)
 
         // The delegate is cleaned up after execution (which happens in another thread), so what we
@@ -458,7 +458,7 @@
     )
     @Test
     fun runnerCreatesDelegateLazily_onAnimationTakeover() {
-        val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = true)
+        val runner = activityTransitionAnimator.createRunner(controller, longLived = true)
         assertNull(runner.delegate)
 
         // The delegate is cleaned up after execution (which happens in another thread), so what we
@@ -489,7 +489,7 @@
     )
     @Test
     fun animationTakeoverThrows_whenTheFlagsAreDisabled() {
-        val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = false)
+        val runner = activityTransitionAnimator.createRunner(controller, longLived = false)
         assertThrows(IllegalStateException::class.java) {
             runner.takeOverAnimation(
                 arrayOf(fakeWindow()),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/back/FlingOnBackAnimationCallbackTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/back/FlingOnBackAnimationCallbackTest.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/animation/back/FlingOnBackAnimationCallbackTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/animation/back/FlingOnBackAnimationCallbackTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
similarity index 99%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
index a4653e7..77db977 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
@@ -29,7 +29,6 @@
 import org.junit.Test
 import platform.test.runner.parameterized.ParameterizedAndroidJunit4
 import platform.test.runner.parameterized.Parameters
-import platform.test.runner.parameterized.Parameter
 import org.junit.runner.RunWith
 
 @SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorTest.kt
index 4d138b4..5d622ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorTest.kt
@@ -122,9 +122,24 @@
 
     @Test
     @DisableFlags(Flags.FLAG_AUDIO_SHARING_QS_DIALOG_IMPROVEMENT)
+    fun testOnClick_connectedAudioSharingMediaDevice_flagOff_previewOn_createDialog() {
+        with(kosmos) {
+            testScope.runTest {
+                whenever(BluetoothUtils.isAudioSharingPreviewEnabled(any())).thenReturn(true)
+                bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
+                actionInteractorImpl.onClick(connectedAudioSharingMediaDeviceItem, dialog)
+                verify(dialogTransitionAnimator)
+                    .showFromDialog(any(), any(), eq(null), anyBoolean())
+            }
+        }
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_AUDIO_SHARING_QS_DIALOG_IMPROVEMENT)
     fun testOnClick_connectedAudioSharingMediaDevice_flagOff_shouldLaunchSettings() {
         with(kosmos) {
             testScope.runTest {
+                whenever(BluetoothUtils.isAudioSharingPreviewEnabled(any())).thenReturn(false)
                 bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true)
                 whenever(cachedBluetoothDevice.device).thenReturn(bluetoothDevice)
                 actionInteractorImpl.onClick(connectedAudioSharingMediaDeviceItem, dialog)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
index 2c17181..bfbdc50 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
@@ -24,9 +24,9 @@
 import android.os.Looper
 import android.os.PatternMatcher
 import android.os.UserHandle
-import androidx.test.filters.SmallTest
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
 import com.android.systemui.dump.DumpManager
@@ -40,8 +40,9 @@
 import junit.framework.Assert.assertSame
 import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.advanceUntilIdle
-import kotlinx.coroutines.test.runBlockingTest
+import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -68,39 +69,28 @@
         val DEFAULT_PERMISSION: String? = null
 
         fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
+
         const val TEST_ACTION = "TEST_ACTION"
         const val TEST_SCHEME = "TEST_SCHEME"
         const val TEST_PATH = "TEST_PATH"
         const val TEST_TYPE = "test/type"
     }
 
-    @Mock
-    private lateinit var mockContext: Context
-    @Mock
-    private lateinit var mockUBRUser0: UserBroadcastDispatcher
-    @Mock
-    private lateinit var mockUBRUser1: UserBroadcastDispatcher
-    @Mock
-    private lateinit var broadcastReceiver: BroadcastReceiver
-    @Mock
-    private lateinit var broadcastReceiverOther: BroadcastReceiver
-    @Mock
-    private lateinit var intentFilter: IntentFilter
-    @Mock
-    private lateinit var intentFilterOther: IntentFilter
-    @Mock
-    private lateinit var mockHandler: Handler
-    @Mock
-    private lateinit var logger: BroadcastDispatcherLogger
-    @Mock
-    private lateinit var userTracker: UserTracker
-    @Mock
-    private lateinit var removalPendingStore: PendingRemovalStore
+    @Mock private lateinit var mockContext: Context
+    @Mock private lateinit var mockUBRUser0: UserBroadcastDispatcher
+    @Mock private lateinit var mockUBRUser1: UserBroadcastDispatcher
+    @Mock private lateinit var broadcastReceiver: BroadcastReceiver
+    @Mock private lateinit var broadcastReceiverOther: BroadcastReceiver
+    @Mock private lateinit var intentFilter: IntentFilter
+    @Mock private lateinit var intentFilterOther: IntentFilter
+    @Mock private lateinit var mockHandler: Handler
+    @Mock private lateinit var logger: BroadcastDispatcherLogger
+    @Mock private lateinit var userTracker: UserTracker
+    @Mock private lateinit var removalPendingStore: PendingRemovalStore
 
     private lateinit var mainExecutor: Executor
 
-    @Captor
-    private lateinit var argumentCaptor: ArgumentCaptor<ReceiverData>
+    @Captor private lateinit var argumentCaptor: ArgumentCaptor<ReceiverData>
 
     private lateinit var testableLooper: TestableLooper
     private lateinit var broadcastDispatcher: BroadcastDispatcher
@@ -112,7 +102,8 @@
         mainExecutor = FakeExecutor(FakeSystemClock())
         `when`(mockContext.mainExecutor).thenReturn(mainExecutor)
 
-        broadcastDispatcher = TestBroadcastDispatcher(
+        broadcastDispatcher =
+            TestBroadcastDispatcher(
                 mockContext,
                 mainExecutor,
                 testableLooper.looper,
@@ -121,7 +112,8 @@
                 logger,
                 userTracker,
                 removalPendingStore,
-                mapOf(0 to mockUBRUser0, 1 to mockUBRUser1))
+                mapOf(0 to mockUBRUser0, 1 to mockUBRUser1),
+            )
 
         // These should be valid filters
         `when`(intentFilter.countActions()).thenReturn(1)
@@ -131,10 +123,18 @@
 
     @Test
     fun testAddingReceiverToCorrectUBR() {
-        broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
-                mockHandler, user0)
         broadcastDispatcher.registerReceiverWithHandler(
-                broadcastReceiverOther, intentFilterOther, mockHandler, user1)
+            broadcastReceiver,
+            intentFilter,
+            mockHandler,
+            user0,
+        )
+        broadcastDispatcher.registerReceiverWithHandler(
+            broadcastReceiverOther,
+            intentFilterOther,
+            mockHandler,
+            user1,
+        )
 
         testableLooper.processAllMessages()
 
@@ -152,7 +152,11 @@
     fun testAddingReceiverToCorrectUBR_executor() {
         broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mainExecutor, user0)
         broadcastDispatcher.registerReceiver(
-                broadcastReceiverOther, intentFilterOther, mainExecutor, user1)
+            broadcastReceiverOther,
+            intentFilterOther,
+            mainExecutor,
+            user1,
+        )
 
         testableLooper.processAllMessages()
 
@@ -169,7 +173,10 @@
     @Test
     fun testAddReceiverDefaultFlag_handler() {
         broadcastDispatcher.registerReceiverWithHandler(
-                broadcastReceiver, intentFilter, mockHandler)
+            broadcastReceiver,
+            intentFilter,
+            mockHandler,
+        )
         testableLooper.processAllMessages()
 
         verify(mockUBRUser0).registerReceiver(capture(argumentCaptor), eq(DEFAULT_FLAG))
@@ -183,7 +190,11 @@
         val flag = 3
 
         broadcastDispatcher.registerReceiverWithHandler(
-                broadcastReceiver, intentFilter, mockHandler, flags = flag)
+            broadcastReceiver,
+            intentFilter,
+            mockHandler,
+            flags = flag,
+        )
         testableLooper.processAllMessages()
 
         verify(mockUBRUser0).registerReceiver(capture(argumentCaptor), eq(flag))
@@ -212,7 +223,7 @@
             broadcastReceiver,
             intentFilter,
             flags = flag,
-            permission = permission
+            permission = permission,
         )
         testableLooper.processAllMessages()
 
@@ -250,10 +261,18 @@
 
     @Test
     fun testRemovingReceiversRemovesFromAllUBR() {
-        broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
-                mockHandler, user0)
-        broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
-                mockHandler, user1)
+        broadcastDispatcher.registerReceiverWithHandler(
+            broadcastReceiver,
+            intentFilter,
+            mockHandler,
+            user0,
+        )
+        broadcastDispatcher.registerReceiverWithHandler(
+            broadcastReceiver,
+            intentFilter,
+            mockHandler,
+            user1,
+        )
 
         broadcastDispatcher.unregisterReceiver(broadcastReceiver)
 
@@ -265,10 +284,18 @@
 
     @Test
     fun testRemoveReceiverFromUser() {
-        broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
-                mockHandler, user0)
-        broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
-                mockHandler, user1)
+        broadcastDispatcher.registerReceiverWithHandler(
+            broadcastReceiver,
+            intentFilter,
+            mockHandler,
+            user0,
+        )
+        broadcastDispatcher.registerReceiverWithHandler(
+            broadcastReceiver,
+            intentFilter,
+            mockHandler,
+            user1,
+        )
 
         broadcastDispatcher.unregisterReceiverForUser(broadcastReceiver, user0)
 
@@ -282,13 +309,17 @@
     fun testRegisterCurrentAsActualUser() {
         `when`(userTracker.userId).thenReturn(user1.identifier)
 
-        broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
-                mockHandler, UserHandle.CURRENT)
+        broadcastDispatcher.registerReceiverWithHandler(
+            broadcastReceiver,
+            intentFilter,
+            mockHandler,
+            UserHandle.CURRENT,
+        )
 
         testableLooper.processAllMessages()
 
-        verify(mockUBRUser1).registerReceiver(
-                capture(argumentCaptor), eq(Context.RECEIVER_EXPORTED))
+        verify(mockUBRUser1)
+            .registerReceiver(capture(argumentCaptor), eq(Context.RECEIVER_EXPORTED))
         assertSame(broadcastReceiver, argumentCaptor.value.receiver)
     }
 
@@ -300,41 +331,38 @@
 
     @Test(expected = IllegalArgumentException::class)
     fun testFilterMustNotContainDataScheme() {
-        val testFilter = IntentFilter(TEST_ACTION).apply {
-            addDataScheme(TEST_SCHEME)
-        }
+        val testFilter = IntentFilter(TEST_ACTION).apply { addDataScheme(TEST_SCHEME) }
         broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
     }
 
     @Test(expected = IllegalArgumentException::class)
     fun testFilterMustNotContainDataAuthority() {
-        val testFilter = IntentFilter(TEST_ACTION).apply {
-            addDataAuthority(mock(IntentFilter.AuthorityEntry::class.java))
-        }
+        val testFilter =
+            IntentFilter(TEST_ACTION).apply {
+                addDataAuthority(mock(IntentFilter.AuthorityEntry::class.java))
+            }
         broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
     }
 
     @Test(expected = IllegalArgumentException::class)
     fun testFilterMustNotContainDataPath() {
-        val testFilter = IntentFilter(TEST_ACTION).apply {
-            addDataPath(TEST_PATH, PatternMatcher.PATTERN_LITERAL)
-        }
+        val testFilter =
+            IntentFilter(TEST_ACTION).apply {
+                addDataPath(TEST_PATH, PatternMatcher.PATTERN_LITERAL)
+            }
         broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
     }
 
     @Test(expected = IllegalArgumentException::class)
     fun testFilterMustNotContainDataType() {
-        val testFilter = IntentFilter(TEST_ACTION).apply {
-            addDataType(TEST_TYPE)
-        }
+        val testFilter = IntentFilter(TEST_ACTION).apply { addDataType(TEST_TYPE) }
         broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
     }
 
     @Test(expected = IllegalArgumentException::class)
     fun testFilterMustNotSetPriority() {
-        val testFilter = IntentFilter(TEST_ACTION).apply {
-            priority = IntentFilter.SYSTEM_HIGH_PRIORITY
-        }
+        val testFilter =
+            IntentFilter(TEST_ACTION).apply { priority = IntentFilter.SYSTEM_HIGH_PRIORITY }
         broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
     }
 
@@ -366,12 +394,14 @@
 
         val inOrderUser0 = inOrder(mockUBRUser0, removalPendingStore)
         inOrderUser0.verify(mockUBRUser0).unregisterReceiver(broadcastReceiver)
-        inOrderUser0.verify(removalPendingStore)
+        inOrderUser0
+            .verify(removalPendingStore)
             .clearPendingRemoval(broadcastReceiver, UserHandle.USER_ALL)
 
         val inOrderUser1 = inOrder(mockUBRUser1, removalPendingStore)
         inOrderUser1.verify(mockUBRUser1).unregisterReceiver(broadcastReceiver)
-        inOrderUser1.verify(removalPendingStore)
+        inOrderUser1
+            .verify(removalPendingStore)
             .clearPendingRemoval(broadcastReceiver, UserHandle.USER_ALL)
     }
 
@@ -385,21 +415,21 @@
 
         val inOrderUser1 = inOrder(mockUBRUser1, removalPendingStore)
         inOrderUser1.verify(mockUBRUser1).unregisterReceiver(broadcastReceiver)
-        inOrderUser1.verify(removalPendingStore)
+        inOrderUser1
+            .verify(removalPendingStore)
             .clearPendingRemoval(broadcastReceiver, user1.identifier)
     }
 
     @Test
-    fun testBroadcastFlow() = runBlockingTest {
-        val flow = broadcastDispatcher.broadcastFlow(intentFilter, user1) { intent, receiver ->
-            intent to receiver
-        }
+    fun testBroadcastFlow() = runTest(UnconfinedTestDispatcher()) {
+        val flow =
+            broadcastDispatcher.broadcastFlow(intentFilter, user1) { intent, receiver ->
+                intent to receiver
+            }
 
         // Collect the values into collectedValues.
         val collectedValues = mutableListOf<Pair<Intent, BroadcastReceiver>>()
-        val job = launch {
-            flow.collect { collectedValues.add(it) }
-        }
+        val job = launch { flow.collect { collectedValues.add(it) } }
 
         testableLooper.processAllMessages()
         verify(mockUBRUser1).registerReceiver(capture(argumentCaptor), eq(DEFAULT_FLAG))
@@ -436,17 +466,18 @@
         logger: BroadcastDispatcherLogger,
         userTracker: UserTracker,
         removalPendingStore: PendingRemovalStore,
-        var mockUBRMap: Map<Int, UserBroadcastDispatcher>
-    ) : BroadcastDispatcher(
-        context,
-        mainExecutor,
-        backgroundRunningLooper,
-        backgroundRunningExecutor,
-        dumpManager,
-        logger,
-        userTracker,
-        removalPendingStore
-    ) {
+        var mockUBRMap: Map<Int, UserBroadcastDispatcher>,
+    ) :
+        BroadcastDispatcher(
+            context,
+            mainExecutor,
+            backgroundRunningLooper,
+            backgroundRunningExecutor,
+            dumpManager,
+            logger,
+            userTracker,
+            removalPendingStore,
+        ) {
         override fun createUBRForUser(userId: Int): UserBroadcastDispatcher {
             return mockUBRMap.getOrDefault(userId, mock(UserBroadcastDispatcher::class.java))
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/education/domain/ui/view/ContextualEduDialogTest.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduDialogTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/education/domain/ui/view/ContextualEduDialogTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
deleted file mode 100644
index c6f01ea..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
+++ /dev/null
@@ -1,230 +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.keyboard.shortcut.ui.viewmodel
-
-import android.content.Context
-import android.content.Context.INPUT_SERVICE
-import android.hardware.input.fakeInputManager
-import android.os.SystemClock
-import android.view.KeyEvent.ACTION_DOWN
-import android.view.KeyEvent.KEYCODE_A
-import android.view.KeyEvent.META_CTRL_ON
-import android.view.KeyEvent.META_META_ON
-import androidx.compose.ui.input.key.KeyEvent
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
-import com.android.systemui.keyboard.shortcut.shortcutCustomizationViewModelFactory
-import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
-import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState
-import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.testCase
-import com.android.systemui.kosmos.testScope
-import com.android.systemui.res.R
-import com.android.systemui.settings.FakeUserTracker
-import com.android.systemui.settings.userTracker
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.kotlin.mock
-import org.mockito.kotlin.whenever
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class ShortcutCustomizationViewModelTest : SysuiTestCase() {
-
-    private val mockUserContext: Context = mock()
-    private val kosmos =
-        Kosmos().also {
-            it.testCase = this
-            it.userTracker = FakeUserTracker(onCreateCurrentUserContext = { mockUserContext })
-        }
-    private val testScope = kosmos.testScope
-    private val inputManager = kosmos.fakeInputManager.inputManager
-    private val helper = kosmos.shortcutHelperTestHelper
-    private val viewModel = kosmos.shortcutCustomizationViewModelFactory.create()
-
-    @Before
-    fun setup() {
-        helper.showFromActivity()
-        whenever(mockUserContext.getSystemService(INPUT_SERVICE)).thenReturn(inputManager)
-    }
-
-    @Test
-    fun uiState_inactiveByDefault() {
-        testScope.runTest {
-            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
-
-            assertThat(uiState).isEqualTo(ShortcutCustomizationUiState.Inactive)
-        }
-    }
-
-    @Test
-    fun uiState_correctlyUpdatedWhenAddShortcutCustomizationIsRequested() {
-        testScope.runTest {
-            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
-            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
-
-            assertThat(uiState).isEqualTo(expectedStandardAddShortcutUiState)
-        }
-    }
-
-    @Test
-    fun uiState_consumedOnAddDialogShown() {
-        testScope.runTest {
-            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
-            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
-            viewModel.onAddShortcutDialogShown()
-
-            assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).isDialogShowing)
-                .isTrue()
-        }
-    }
-
-    @Test
-    fun uiState_inactiveAfterDialogIsDismissed() {
-        testScope.runTest {
-            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
-            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
-            viewModel.onAddShortcutDialogShown()
-            viewModel.onDialogDismissed()
-            assertThat(uiState).isEqualTo(ShortcutCustomizationUiState.Inactive)
-        }
-    }
-
-    @Test
-    fun uiState_pressedKeys_emptyByDefault() {
-        testScope.runTest {
-            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
-            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
-            assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).pressedKeys)
-                .isEmpty()
-        }
-    }
-
-    @Test
-    fun onKeyPressed_handlesKeyEvents_whereActionKeyIsAlsoPressed() {
-        testScope.runTest {
-            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
-            val isHandled = viewModel.onKeyPressed(keyDownEventWithActionKeyPressed)
-
-            assertThat(isHandled).isTrue()
-        }
-    }
-
-    @Test
-    fun onKeyPressed_doesNotHandleKeyEvents_whenActionKeyIsNotAlsoPressed() {
-        testScope.runTest {
-            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
-            val isHandled = viewModel.onKeyPressed(keyDownEventWithoutActionKeyPressed)
-
-            assertThat(isHandled).isFalse()
-        }
-    }
-
-    @Test
-    fun onKeyPressed_convertsKeyEventsAndUpdatesUiStatesPressedKey() {
-        testScope.runTest {
-            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
-            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
-            viewModel.onKeyPressed(keyDownEventWithActionKeyPressed)
-            viewModel.onKeyPressed(keyUpEventWithActionKeyPressed)
-
-            // Note that Action Key is excluded as it's already displayed on the UI
-            assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).pressedKeys)
-                .containsExactly(ShortcutKey.Text("Ctrl"), ShortcutKey.Text("A"))
-        }
-    }
-
-    @Test
-    fun uiState_pressedKeys_resetsToEmptyListAfterDialogIsDismissedAndReopened() {
-        testScope.runTest {
-            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
-            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
-            viewModel.onKeyPressed(keyDownEventWithActionKeyPressed)
-            viewModel.onKeyPressed(keyUpEventWithActionKeyPressed)
-
-            // Note that Action Key is excluded as it's already displayed on the UI
-            assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).pressedKeys)
-                .containsExactly(ShortcutKey.Text("Ctrl"), ShortcutKey.Text("A"))
-
-            // Close the dialog and show it again
-            viewModel.onDialogDismissed()
-            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
-            assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).pressedKeys)
-                .isEmpty()
-        }
-    }
-
-    private val keyDownEventWithoutActionKeyPressed =
-        KeyEvent(
-            android.view.KeyEvent(
-                /* downTime = */ SystemClock.uptimeMillis(),
-                /* eventTime = */ SystemClock.uptimeMillis(),
-                /* action = */ ACTION_DOWN,
-                /* code = */ KEYCODE_A,
-                /* repeat = */ 0,
-                /* metaState = */ META_CTRL_ON,
-            )
-        )
-
-    private val keyDownEventWithActionKeyPressed =
-        KeyEvent(
-            android.view.KeyEvent(
-                /* downTime = */ SystemClock.uptimeMillis(),
-                /* eventTime = */ SystemClock.uptimeMillis(),
-                /* action = */ ACTION_DOWN,
-                /* code = */ KEYCODE_A,
-                /* repeat = */ 0,
-                /* metaState = */ META_CTRL_ON or META_META_ON,
-            )
-        )
-
-    private val keyUpEventWithActionKeyPressed =
-        KeyEvent(
-            android.view.KeyEvent(
-                /* downTime = */ SystemClock.uptimeMillis(),
-                /* eventTime = */ SystemClock.uptimeMillis(),
-                /* action = */ ACTION_DOWN,
-                /* code = */ KEYCODE_A,
-                /* repeat = */ 0,
-                /* metaState = */ 0,
-            )
-        )
-
-    private val standardAddShortcutRequest =
-        ShortcutCustomizationRequestInfo.Add(
-            label = "Standard shortcut",
-            categoryType = ShortcutCategoryType.System,
-            subCategoryLabel = "Standard subcategory",
-        )
-
-    private val expectedStandardAddShortcutUiState =
-        ShortcutCustomizationUiState.AddShortcutDialog(
-            shortcutLabel = "Standard shortcut",
-            shouldShowErrorMessage = false,
-            defaultCustomShortcutModifierKey =
-                ShortcutKey.Icon.ResIdIcon(R.drawable.ic_ksh_key_meta),
-            isDialogShowing = false,
-        )
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
index feae901..3bd2496 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
@@ -413,6 +413,7 @@
                 key("Ctrl")
                 key("A")
             }
+            contentDescription { "$label, Press key Ctrl plus A" }
         }
 
     companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index 929b0aa..67e03e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -273,6 +273,12 @@
                     "${Contract.AUTHORITY}." +
                     Contract.FlagsTable.TABLE_NAME
             )
+        assertThat(underTest.getType(Contract.RuntimeValuesTable.URI))
+            .isEqualTo(
+                "vnd.android.cursor.dir/vnd." +
+                    "${Contract.AUTHORITY}." +
+                    Contract.RuntimeValuesTable.TABLE_NAME
+            )
     }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java
index bf4ef50..7ba797c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java
@@ -59,6 +59,7 @@
 import android.os.PowerExemptionManager;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.service.notification.StatusBarNotification;
 import android.testing.TestableLooper;
@@ -242,10 +243,14 @@
         mLocalMediaManager = spy(mMediaSwitchingController.mLocalMediaManager);
         when(mLocalMediaManager.isPreferenceRouteListingExist()).thenReturn(false);
         mMediaSwitchingController.mLocalMediaManager = mLocalMediaManager;
+
         mMediaSwitchingController.mInputRouteManager =
                 new InputRouteManager(mContext, mAudioManager);
         mInputRouteManager = spy(mMediaSwitchingController.mInputRouteManager);
         mMediaSwitchingController.mInputRouteManager = mInputRouteManager;
+        when(mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS))
+                .thenReturn(new AudioDeviceInfo[0]);
+
         MediaDescription.Builder builder = new MediaDescription.Builder();
         builder.setTitle(TEST_SONG);
         builder.setSubtitle(TEST_ARTIST);
@@ -483,11 +488,11 @@
         verify(mMediaDevice2, never()).setRangeZone(anyInt());
     }
 
+    @DisableFlags(Flags.FLAG_ENABLE_AUDIO_INPUT_DEVICE_ROUTING_AND_VOLUME_CONTROL)
     @Test
     public void onDeviceListUpdate_verifyDeviceListCallback() {
         // This test relies on mMediaSwitchingController.start being called while the selected
-        // device
-        // list has exactly one item, and that item's id is:
+        // device list has exactly one item, and that item's id is:
         // - Different from both ids in mMediaDevices.
         // - Different from the id of the route published by the device under test (usually the
         //   built-in speakers).
@@ -511,16 +516,54 @@
 
         assertThat(devices.containsAll(mMediaDevices)).isTrue();
         assertThat(devices.size()).isEqualTo(mMediaDevices.size());
+        // There should be 2 non-MediaDevice items: the "Speakers & Display" title, and the "Connect
+        // a device" button.
         assertThat(mMediaSwitchingController.getMediaItemList().size())
                 .isEqualTo(mMediaDevices.size() + 2);
         verify(mCb).onDeviceListChanged();
     }
 
+    @EnableFlags(Flags.FLAG_ENABLE_AUDIO_INPUT_DEVICE_ROUTING_AND_VOLUME_CONTROL)
+    @Test
+    public void onDeviceListUpdate_verifyDeviceListCallback_inputRouting() {
+        // This test relies on mMediaSwitchingController.start being called while the selected
+        // device list has exactly one item, and that item's id is:
+        // - Different from both ids in mMediaDevices.
+        // - Different from the id of the route published by the device under test (usually the
+        //   built-in speakers).
+        // So mock the selected device to respect these two preconditions.
+        MediaDevice mockSelectedMediaDevice = Mockito.mock(MediaDevice.class);
+        when(mockSelectedMediaDevice.getId()).thenReturn(TEST_DEVICE_3_ID);
+        doReturn(List.of(mockSelectedMediaDevice))
+                .when(mLocalMediaManager)
+                .getSelectedMediaDevice();
+
+        mMediaSwitchingController.start(mCb);
+        reset(mCb);
+
+        mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
+        final List<MediaDevice> devices = new ArrayList<>();
+        for (MediaItem item : mMediaSwitchingController.getMediaItemList()) {
+            if (item.getMediaDevice().isPresent()) {
+                devices.add(item.getMediaDevice().get());
+            }
+        }
+
+        assertThat(devices.containsAll(mMediaDevices)).isTrue();
+        assertThat(devices.size()).isEqualTo(mMediaDevices.size());
+        // When input routing is enabled, there should be 4 non-MediaDevice items: one for
+        // the "Output" title, one for the "Speakers & Displays" title, one for the "Connect a
+        // device" button, and one for the "Input" title.
+        assertThat(mMediaSwitchingController.getMediaItemList().size())
+                .isEqualTo(mMediaDevices.size() + 4);
+        verify(mCb).onDeviceListChanged();
+    }
+
+    @DisableFlags(Flags.FLAG_ENABLE_AUDIO_INPUT_DEVICE_ROUTING_AND_VOLUME_CONTROL)
     @Test
     public void advanced_onDeviceListUpdateWithConnectedDeviceRemote_verifyItemSize() {
         // This test relies on mMediaSwitchingController.start being called while the selected
-        // device
-        // list has exactly one item, and that item's id is:
+        // device list has exactly one item, and that item's id is:
         // - Different from both ids in mMediaDevices.
         // - Different from the id of the route published by the device under test (usually the
         //   built-in speakers).
@@ -547,6 +590,7 @@
 
         assertThat(devices.containsAll(mMediaDevices)).isTrue();
         assertThat(devices.size()).isEqualTo(mMediaDevices.size());
+        // There should be 1 non-MediaDevice item: the "Speakers & Display" title.
         assertThat(mMediaSwitchingController.getMediaItemList().size())
                 .isEqualTo(mMediaDevices.size() + 1);
         verify(mCb).onDeviceListChanged();
@@ -554,6 +598,45 @@
 
     @EnableFlags(Flags.FLAG_ENABLE_AUDIO_INPUT_DEVICE_ROUTING_AND_VOLUME_CONTROL)
     @Test
+    public void advanced_onDeviceListUpdateWithConnectedDeviceRemote_verifyItemSize_inputRouting() {
+        // This test relies on mMediaSwitchingController.start being called while the selected
+        // device list has exactly one item, and that item's id is:
+        // - Different from both ids in mMediaDevices.
+        // - Different from the id of the route published by the device under test (usually the
+        //   built-in speakers).
+        // So mock the selected device to respect these two preconditions.
+        MediaDevice mockSelectedMediaDevice = Mockito.mock(MediaDevice.class);
+        when(mockSelectedMediaDevice.getId()).thenReturn(TEST_DEVICE_3_ID);
+        doReturn(List.of(mockSelectedMediaDevice))
+                .when(mLocalMediaManager)
+                .getSelectedMediaDevice();
+
+        when(mMediaDevice1.getFeatures())
+                .thenReturn(ImmutableList.of(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK));
+        when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice1);
+        mMediaSwitchingController.start(mCb);
+        reset(mCb);
+
+        mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
+        final List<MediaDevice> devices = new ArrayList<>();
+        for (MediaItem item : mMediaSwitchingController.getMediaItemList()) {
+            if (item.getMediaDevice().isPresent()) {
+                devices.add(item.getMediaDevice().get());
+            }
+        }
+
+        assertThat(devices.containsAll(mMediaDevices)).isTrue();
+        assertThat(devices.size()).isEqualTo(mMediaDevices.size());
+        // When input routing is enabled, there should be 3 non-MediaDevice items: one for
+        // the "Output" title, one for the "Speakers & Displays" title, and one for the "Input"
+        // title.
+        assertThat(mMediaSwitchingController.getMediaItemList().size())
+                .isEqualTo(mMediaDevices.size() + 3);
+        verify(mCb).onDeviceListChanged();
+    }
+
+    @EnableFlags(Flags.FLAG_ENABLE_AUDIO_INPUT_DEVICE_ROUTING_AND_VOLUME_CONTROL)
+    @Test
     public void onInputDeviceListUpdate_verifyDeviceListCallback() {
         AudioDeviceInfo[] audioDeviceInfos = {};
         when(mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS))
@@ -1384,4 +1467,66 @@
         verify(mInputRouteManager, never()).selectDevice(outputMediaDevice);
         verify(mLocalMediaManager, atLeastOnce()).connectDevice(outputMediaDevice);
     }
+
+    @DisableFlags(Flags.FLAG_ENABLE_AUDIO_INPUT_DEVICE_ROUTING_AND_VOLUME_CONTROL)
+    @Test
+    public void connectDeviceButton_presentAtAllTimesForNonGroupOutputs() {
+        mMediaSwitchingController.start(mCb);
+        reset(mCb);
+
+        // Mock the selected output device.
+        doReturn(Collections.singletonList(mMediaDevice1))
+                .when(mLocalMediaManager)
+                .getSelectedMediaDevice();
+
+        // Verify that there is initially one "Connect a device" button present.
+        assertThat(getNumberOfConnectDeviceButtons()).isEqualTo(1);
+
+        // Change the selected device, and verify that there is still one "Connect a device" button
+        // present.
+        doReturn(Collections.singletonList(mMediaDevice2))
+                .when(mLocalMediaManager)
+                .getSelectedMediaDevice();
+        mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
+
+        assertThat(getNumberOfConnectDeviceButtons()).isEqualTo(1);
+    }
+
+    @EnableFlags(Flags.FLAG_ENABLE_AUDIO_INPUT_DEVICE_ROUTING_AND_VOLUME_CONTROL)
+    @Test
+    public void connectDeviceButton_presentAtAllTimesForNonGroupOutputs_inputRoutingEnabled() {
+        mMediaSwitchingController.start(mCb);
+        reset(mCb);
+
+        // Mock the selected output device.
+        doReturn(Collections.singletonList(mMediaDevice1))
+                .when(mLocalMediaManager)
+                .getSelectedMediaDevice();
+
+        // Mock the selected input media device.
+        final MediaDevice selectedInputMediaDevice = mock(MediaDevice.class);
+        doReturn(selectedInputMediaDevice).when(mInputRouteManager).getSelectedInputDevice();
+
+        // Verify that there is initially one "Connect a device" button present.
+        assertThat(getNumberOfConnectDeviceButtons()).isEqualTo(1);
+
+        // Change the selected device, and verify that there is still one "Connect a device" button
+        // present.
+        doReturn(Collections.singletonList(mMediaDevice2))
+                .when(mLocalMediaManager)
+                .getSelectedMediaDevice();
+        mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
+
+        assertThat(getNumberOfConnectDeviceButtons()).isEqualTo(1);
+    }
+
+    private int getNumberOfConnectDeviceButtons() {
+        int numberOfConnectDeviceButtons = 0;
+        for (MediaItem item : mMediaSwitchingController.getMediaItemList()) {
+            if (item.getMediaItemType() == MediaItem.MediaItemType.TYPE_PAIR_NEW_DEVICE) {
+                numberOfConnectDeviceButtons++;
+            }
+        }
+        return numberOfConnectDeviceButtons;
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java
index bc3c0d9..d59a404 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java
@@ -49,6 +49,7 @@
 import com.android.dx.mockito.inline.extended.StaticMockitoSession;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.views.NavigationBar;
 import com.android.systemui.recents.OverviewProxyService;
@@ -56,7 +57,7 @@
 import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.AutoHideControllerStore;
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -89,6 +90,11 @@
 
     private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
 
+    private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
+
+    private final AutoHideControllerStore mAutoHideControllerStore =
+            mKosmos.getAutoHideControllerStore();
+
     @Mock
     private CommandQueue mCommandQueue;
     @Mock
@@ -113,7 +119,7 @@
                         mTaskbarDelegate,
                         mNavigationBarFactory,
                         mock(DumpManager.class),
-                        mock(AutoHideController.class),
+                        mAutoHideControllerStore,
                         mock(LightBarController.class),
                         TaskStackChangeListeners.getTestInstance(),
                         Optional.of(mock(Pip.class)),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt
index fac5ecb..f23553e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt
@@ -23,6 +23,7 @@
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.click
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithContentDescription
 import androidx.compose.ui.test.performClick
@@ -73,7 +74,7 @@
     }
 
     @Test
-    fun toggleIconTile_shouldBeLarge() {
+    fun toggleIconTileWithA11yAction_shouldBeLarge() {
         var tiles by mutableStateOf(TestEditTiles)
         val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2)
         composeRule.setContent {
@@ -89,7 +90,7 @@
     }
 
     @Test
-    fun toggleLargeTile_shouldBeIcon() {
+    fun toggleLargeTileWithA11yAction_shouldBeIcon() {
         var tiles by mutableStateOf(TestEditTiles)
         val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2)
         composeRule.setContent {
@@ -105,7 +106,7 @@
     }
 
     @Test
-    fun resizedLarge_shouldBeIcon() {
+    fun tapOnIconResizingHandle_shouldBeLarge() {
         var tiles by mutableStateOf(TestEditTiles)
         val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2)
         composeRule.setContent {
@@ -116,12 +117,32 @@
         composeRule
             .onNodeWithContentDescription("tileA")
             .performClick() // Select
-            .performTouchInput { // Resize down
-                swipeRight()
+            .performTouchInput { // Tap on resizing handle
+                click(centerRight)
             }
         composeRule.waitForIdle()
 
-        assertThat(tiles.find { it.tile.tileSpec.spec == "tileA" }?.width).isEqualTo(1)
+        assertThat(tiles.find { it.tile.tileSpec.spec == "tileA" }?.width).isEqualTo(2)
+    }
+
+    @Test
+    fun tapOnLargeResizingHandle_shouldBeIcon() {
+        var tiles by mutableStateOf(TestEditTiles)
+        val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2)
+        composeRule.setContent {
+            EditTileGridUnderTest(listState) { spec, toIcon -> tiles = tiles.resize(spec, toIcon) }
+        }
+        composeRule.waitForIdle()
+
+        composeRule
+            .onNodeWithContentDescription("tileD_large")
+            .performClick() // Select
+            .performTouchInput { // Tap on resizing handle
+                click(centerRight)
+            }
+        composeRule.waitForIdle()
+
+        assertThat(tiles.find { it.tile.tileSpec.spec == "tileD_large" }?.width).isEqualTo(1)
     }
 
     @Test
@@ -134,6 +155,26 @@
         composeRule.waitForIdle()
 
         composeRule
+            .onNodeWithContentDescription("tileA")
+            .performClick() // Select
+            .performTouchInput { // Resize up
+                swipeRight(startX = right, endX = right * 2)
+            }
+        composeRule.waitForIdle()
+
+        assertThat(tiles.find { it.tile.tileSpec.spec == "tileA" }?.width).isEqualTo(2)
+    }
+
+    @Test
+    fun resizedLarge_shouldBeIcon() {
+        var tiles by mutableStateOf(TestEditTiles)
+        val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2)
+        composeRule.setContent {
+            EditTileGridUnderTest(listState) { spec, toIcon -> tiles = tiles.resize(spec, toIcon) }
+        }
+        composeRule.waitForIdle()
+
+        composeRule
             .onNodeWithContentDescription("tileD_large")
             .performClick() // Select
             .performTouchInput { // Resize down
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
index f7059e2..a64ff321 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.brightness.ui.viewmodel.BrightnessSliderViewModel
 import com.android.systemui.brightness.ui.viewmodel.brightnessSliderViewModelFactory
 import com.android.systemui.qs.flags.QSComposeFragment
+import com.android.systemui.qs.flags.QsInCompose
 import com.android.systemui.res.R
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
@@ -70,8 +71,8 @@
         mSetFlagsRule.setFlagsParameterization(flags)
     }
 
-    val viewId by lazy {
-        if (QSComposeFragment.isEnabled) {
+    private val viewId by lazy {
+        if (QsInCompose.isEnabled) {
             R.id.brightness_dialog_slider
         } else {
             R.id.brightness_mirror_container
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
index 859f84e..e7fb470c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
@@ -33,6 +33,7 @@
 import androidx.test.filters.SmallTest
 import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.Flags
+import com.android.systemui.Flags.FLAG_COMMUNAL_HUB_ON_MOBILE
 import com.android.systemui.Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.ambient.touch.TouchHandler
@@ -630,6 +631,7 @@
             }
         }
 
+    @DisableFlags(FLAG_COMMUNAL_HUB_ON_MOBILE)
     @Test
     fun onTouchEvent_shadeInteracting_movesNotDispatched() =
         with(kosmos) {
@@ -686,6 +688,7 @@
             }
         }
 
+    @DisableFlags(FLAG_COMMUNAL_HUB_ON_MOBILE)
     @Test
     fun onTouchEvent_bouncerInteracting_movesNotDispatched() =
         with(kosmos) {
@@ -718,6 +721,19 @@
             }
         }
 
+    @EnableFlags(FLAG_COMMUNAL_HUB_ON_MOBILE)
+    @Test
+    fun onTouchEvent_onLockscreenAndGlanceableHubV2_touchIgnored() =
+        with(kosmos) {
+            testScope.runTest {
+                // On lockscreen.
+                goToScene(CommunalScenes.Blank)
+
+                assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
+                verify(containerView, never()).onTouchEvent(DOWN_EVENT)
+            }
+        }
+
     @Test
     fun disposeView_destroysTouchMonitor() {
         clearInvocations(touchMonitor)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index 61d14b7..58864f6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -76,7 +76,7 @@
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.FakeEventLog;
 import com.android.systemui.util.settings.FakeGlobalSettings;
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 f870200..28577b3 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
@@ -61,7 +61,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.time.FakeSystemClock;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index d8a23d6..5aee929 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -68,6 +68,7 @@
 import com.android.systemui.statusbar.notification.FeedbackIcon;
 import com.android.systemui.statusbar.notification.SourceType;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.headsup.PinnedStatus;
 import com.android.systemui.statusbar.notification.row.ExpandableView.OnHeightChangedListener;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 import com.android.systemui.statusbar.notification.shared.NotificationContentAlphaOptimization;
@@ -394,7 +395,7 @@
         ExpandableNotificationRow row = mNotificationTestHelper.createRow();
         AboveShelfChangedListener listener = mock(AboveShelfChangedListener.class);
         row.setAboveShelfChangedListener(listener);
-        row.setPinned(true);
+        row.setPinnedStatus(PinnedStatus.PinnedBySystem);
         verify(listener).onAboveShelfStateChanged(true);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
index 723c0d7..2d35ea5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
@@ -65,11 +65,11 @@
 import com.android.systemui.statusbar.notification.NotificationActivityStarter
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
 import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
+import com.android.systemui.statusbar.notification.headsup.headsUpManager
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
 import com.android.systemui.statusbar.notificationLockscreenUserManager
 import com.android.systemui.statusbar.policy.deviceProvisionedController
-import com.android.systemui.statusbar.policy.headsUpManager
 import com.android.systemui.testKosmos
 import com.android.systemui.util.kotlin.JavaAdapter
 import com.android.systemui.wmshell.BubblesManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index d2350bc..11b19f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -103,7 +103,7 @@
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.policy.AvalancheController;
+import com.android.systemui.statusbar.notification.headsup.AvalancheController;
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
 import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index c9f8463..6912eda 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -198,7 +198,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.ExtensionController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.window.StatusBarWindowController;
@@ -334,7 +334,7 @@
     @Mock private CentralSurfacesCommandQueueCallbacks mCentralSurfacesCommandQueueCallbacks;
     @Mock private PluginManager mPluginManager;
     @Mock private ViewMediatorCallback mViewMediatorCallback;
-    @Mock private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
+    @Mock private ShadeTouchableRegionManager mShadeTouchableRegionManager;
     @Mock private PluginDependencyProvider mPluginDependencyProvider;
     @Mock private ExtensionController mExtensionController;
     @Mock private UserInfoControllerImpl mUserInfoControllerImpl;
@@ -617,7 +617,7 @@
                 mKeyguardIndicationController,
                 mDemoModeController,
                 mNotificationShadeDepthControllerLazy,
-                mStatusBarTouchableRegionManager,
+                mShadeTouchableRegionManager,
                 mBrightnessSliderFactory,
                 mScreenOffAnimationController,
                 mWallpaperController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index cace60c..2f30b74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -95,7 +95,7 @@
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index a213c85..1d4b8e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -58,6 +58,7 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
 
 import kotlin.sequences.Sequence;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index aad8b4b..a1c9022e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -141,6 +141,7 @@
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.notification.interruption.AvalancheProvider;
 import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
@@ -154,7 +155,6 @@
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -2575,78 +2575,6 @@
 
     @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
     @Test
-    public void testEventLogging_bubbleBar_dragBarLeft() {
-        mBubbleProperties.mIsBubbleBarEnabled = true;
-        mPositioner.setIsLargeScreen(true);
-        mPositioner.setBubbleBarLocation(BubbleBarLocation.RIGHT);
-        FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
-        mBubbleController.registerBubbleStateListener(bubbleStateListener);
-
-        mEntryListener.onEntryAdded(mRow);
-        assertBarMode();
-
-        mBubbleController.setBubbleBarLocation(BubbleBarLocation.LEFT,
-                BubbleBarLocation.UpdateSource.DRAG_BAR);
-
-        verify(mBubbleLogger).log(BubbleLogger.Event.BUBBLE_BAR_MOVED_LEFT_DRAG_BAR);
-    }
-
-    @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
-    @Test
-    public void testEventLogging_bubbleBar_dragBarRight() {
-        mBubbleProperties.mIsBubbleBarEnabled = true;
-        mPositioner.setIsLargeScreen(true);
-        mPositioner.setBubbleBarLocation(BubbleBarLocation.LEFT);
-        FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
-        mBubbleController.registerBubbleStateListener(bubbleStateListener);
-
-        mEntryListener.onEntryAdded(mRow);
-        assertBarMode();
-
-        mBubbleController.setBubbleBarLocation(BubbleBarLocation.RIGHT,
-                BubbleBarLocation.UpdateSource.DRAG_BAR);
-
-        verify(mBubbleLogger).log(BubbleLogger.Event.BUBBLE_BAR_MOVED_RIGHT_DRAG_BAR);
-    }
-
-    @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
-    @Test
-    public void testEventLogging_bubbleBar_dragBubbleLeft() {
-        mBubbleProperties.mIsBubbleBarEnabled = true;
-        mPositioner.setIsLargeScreen(true);
-        mPositioner.setBubbleBarLocation(BubbleBarLocation.RIGHT);
-        FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
-        mBubbleController.registerBubbleStateListener(bubbleStateListener);
-
-        mEntryListener.onEntryAdded(mRow);
-        assertBarMode();
-
-        mBubbleController.setBubbleBarLocation(BubbleBarLocation.LEFT,
-                BubbleBarLocation.UpdateSource.DRAG_BUBBLE);
-
-        verify(mBubbleLogger).log(BubbleLogger.Event.BUBBLE_BAR_MOVED_LEFT_DRAG_BUBBLE);
-    }
-
-    @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
-    @Test
-    public void testEventLogging_bubbleBar_dragBubbleRight() {
-        mBubbleProperties.mIsBubbleBarEnabled = true;
-        mPositioner.setIsLargeScreen(true);
-        mPositioner.setBubbleBarLocation(BubbleBarLocation.LEFT);
-        FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
-        mBubbleController.registerBubbleStateListener(bubbleStateListener);
-
-        mEntryListener.onEntryAdded(mRow);
-        assertBarMode();
-
-        mBubbleController.setBubbleBarLocation(BubbleBarLocation.RIGHT,
-                BubbleBarLocation.UpdateSource.DRAG_BUBBLE);
-
-        verify(mBubbleLogger).log(BubbleLogger.Event.BUBBLE_BAR_MOVED_RIGHT_DRAG_BUBBLE);
-    }
-
-    @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
-    @Test
     public void testEventLogging_bubbleBar_expandAndCollapse() {
         mBubbleProperties.mIsBubbleBarEnabled = true;
         mPositioner.setIsLargeScreen(true);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt
index 5063140..0ba7c85 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt
@@ -62,6 +62,7 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
 import com.android.systemui.statusbar.notification.collection.NotifCollection
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger
 import com.android.systemui.statusbar.notification.stack.AmbientState
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
@@ -74,7 +75,6 @@
 import com.android.systemui.statusbar.phone.ScrimController
 import com.android.systemui.statusbar.phone.SystemUIDialogManager
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.statusbar.policy.ZenModeController
 import com.android.systemui.statusbar.window.StatusBarWindowController
@@ -173,7 +173,7 @@
     interface Bindings {
         @Binds
         fun bindStatusBarStateController(
-            sysuiStatusBarStateController: SysuiStatusBarStateController,
+            sysuiStatusBarStateController: SysuiStatusBarStateController
         ): StatusBarStateController
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/MotionEventHelper.java b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/MotionEventHelper.java
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/MotionEventHelper.java
rename to packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/MotionEventHelper.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/TestableWindowManager.java b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/TestableWindowManager.java
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/TestableWindowManager.java
rename to packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/TestableWindowManager.java
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/activity/data/repository/ActivityManagerRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/activity/data/repository/ActivityManagerRepositoryKosmos.kt
new file mode 100644
index 0000000..a6e7133
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/activity/data/repository/ActivityManagerRepositoryKosmos.kt
@@ -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.systemui.activity.data.repository
+
+import android.app.activityManager
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.log.core.Logger
+import kotlinx.coroutines.flow.MutableStateFlow
+
+val Kosmos.activityManagerRepository by Kosmos.Fixture { FakeActivityManagerRepository() }
+
+val Kosmos.realActivityManagerRepository by
+    Kosmos.Fixture { ActivityManagerRepositoryImpl(testDispatcher, activityManager) }
+
+class FakeActivityManagerRepository : ActivityManagerRepository {
+    private val uidFlows = mutableMapOf<Int, MutableList<MutableStateFlow<Boolean>>>()
+
+    var startingIsAppVisibleValue = false
+
+    override fun createIsAppVisibleFlow(
+        creationUid: Int,
+        logger: Logger,
+        identifyingLogTag: String,
+    ): MutableStateFlow<Boolean> {
+        val newFlow = MutableStateFlow(startingIsAppVisibleValue)
+        uidFlows.computeIfAbsent(creationUid) { mutableListOf() }.add(newFlow)
+        return newFlow
+    }
+
+    fun setIsAppVisible(uid: Int, isAppVisible: Boolean) {
+        uidFlows[uid]?.forEach { stateFlow -> stateFlow.value = isAppVisible }
+    }
+}
+
+val ActivityManagerRepository.fake
+    get() = this as FakeActivityManagerRepository
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/AnimatorTestRule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/AnimatorTestRule.kt
index e2fc44f..eb0aee4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/AnimatorTestRule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/AnimatorTestRule.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.animation
 
+import android.animation.Animator
 import java.util.function.Consumer
 import org.junit.rules.RuleChain
 import org.junit.rules.TestRule
@@ -71,6 +72,22 @@
     }
 
     /**
+     * This is similar to [advanceTimeBy] but it expects to reach the end of an animation. This call
+     * may produce 2 frames for the last animation frame and end animation callback.
+     *
+     * @param durationMs the duration that is greater than or equal to the animation duration.
+     */
+    fun advanceAnimationDuration(durationMs: Long) {
+        advanceTimeBy(durationMs)
+        if (Animator.isPostNotifyEndListenerEnabled()) {
+            // If the post-end-callback is enabled, the AnimatorListener#onAnimationEnd will be
+            // called on the next frame of last animation frame. So trigger additional doFrame to
+            // ensure the end callback method is called (by android.animation.AnimatorTestRule).
+            advanceTimeBy(0)
+        }
+    }
+
+    /**
      * Returns the current time in milliseconds tracked by the AnimationHandlers. Note that this is
      * a different time than the time tracked by {@link SystemClock}.
      */
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorKosmos.kt
index 4f4d1da..e0c0fbd 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorKosmos.kt
@@ -16,12 +16,14 @@
 
 package com.android.systemui.bluetooth.qsdialog
 
+import android.content.applicationContext
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.testDispatcher
 
 val Kosmos.audioSharingInteractor: AudioSharingInteractor by
     Kosmos.Fixture {
         AudioSharingInteractorImpl(
+            applicationContext,
             localBluetoothManager,
             bluetoothTileDialogAudioSharingRepository,
             testDispatcher,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt
index e0d1d16..7254154 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer
 import com.android.systemui.haptics.msdl.bouncerHapticPlayer
 import com.android.systemui.inputmethod.domain.interactor.inputMethodInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardDismissActionInteractor
 import com.android.systemui.keyguard.domain.interactor.keyguardMediaKeyInteractor
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
@@ -63,6 +64,7 @@
         bouncerHapticPlayer = bouncerHapticPlayer,
         keyguardMediaKeyInteractor = keyguardMediaKeyInteractor,
         bouncerActionButtonInteractor = bouncerActionButtonInteractor,
+        keyguardDismissActionInteractor = keyguardDismissActionInteractor,
     )
 }
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelKosmos.kt
index e36ad42..35e85bb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelKosmos.kt
@@ -18,6 +18,7 @@
 
 import com.android.systemui.brightness.domain.interactor.brightnessPolicyEnforcementInteractor
 import com.android.systemui.brightness.domain.interactor.screenBrightnessInteractor
+import com.android.systemui.classifier.domain.interactor.falsingInteractor
 import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.settings.brightness.domain.interactor.brightnessMirrorShowingInteractor
@@ -33,6 +34,7 @@
                     hapticsViewModelFactory = sliderHapticsViewModelFactory,
                     brightnessMirrorShowingInteractor = brightnessMirrorShowingInteractor,
                     supportsMirroring = allowsMirroring,
+                    falsingInteractor = falsingInteractor,
                     brightnessWarningToast = brightnessWarningToast,
                 )
             }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryKosmos.kt
index 5485f79..5da6c7b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryKosmos.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.communal.data.repository
 
 import android.app.admin.devicePolicyManager
+import android.content.res.mainResources
 import com.android.systemui.broadcast.broadcastDispatcher
 import com.android.systemui.flags.featureFlagsClassic
 import com.android.systemui.kosmos.Kosmos
@@ -27,6 +28,7 @@
     Kosmos.Fixture {
         CommunalSettingsRepositoryImpl(
             bgDispatcher = testDispatcher,
+            resources = mainResources,
             featureFlagsClassic = featureFlagsClassic,
             secureSettings = fakeSettings,
             broadcastDispatcher = broadcastDispatcher,
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 78ea700..ddcc926 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
@@ -57,6 +57,10 @@
         addDisplay(display(type, id = displayId))
     }
 
+    suspend fun addDisplays(vararg displays: Display) {
+        displays.forEach { addDisplay(it) }
+    }
+
     suspend fun addDisplay(display: Display) {
         flow.value += display
         displayAdditionEventFlow.emit(display)
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/packages/SystemUI/tests/utils/src/com/android/systemui/display/domain/interactor/DisplayWindowPropertiesInteractorKosmos.kt
similarity index 64%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to packages/SystemUI/tests/utils/src/com/android/systemui/display/domain/interactor/DisplayWindowPropertiesInteractorKosmos.kt
index 7d3d8b9..c2466bb 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/domain/interactor/DisplayWindowPropertiesInteractorKosmos.kt
@@ -13,10 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
-}
+package com.android.systemui.display.domain.interactor
+
+import com.android.systemui.display.data.repository.displayWindowPropertiesRepository
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.displayWindowPropertiesInteractor by
+    Kosmos.Fixture { DisplayWindowPropertiesInteractorImpl(displayWindowPropertiesRepository) }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeServiceFake.java b/packages/SystemUI/tests/utils/src/com/android/systemui/doze/DozeServiceFake.java
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeServiceFake.java
rename to packages/SystemUI/tests/utils/src/com/android/systemui/doze/DozeServiceFake.java
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelKosmos.kt
index b24b3ad..71746b5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelKosmos.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.dreams.ui.viewmodel
 
+import com.android.systemui.communal.domain.interactor.communalInteractor
 import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.shade.domain.interactor.shadeInteractor
@@ -23,6 +24,7 @@
 val Kosmos.dreamUserActionsViewModel by
     Kosmos.Fixture {
         DreamUserActionsViewModel(
+            communalInteractor = communalInteractor,
             deviceUnlockedInteractor = deviceUnlockedInteractor,
             shadeInteractor = shadeInteractor,
         )
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
index 9cb15c5..e7672ff 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
@@ -24,6 +24,7 @@
 import com.android.systemui.broadcast.broadcastDispatcher
 import com.android.systemui.keyboard.shortcut.data.repository.CustomShortcutCategoriesRepository
 import com.android.systemui.keyboard.shortcut.data.repository.DefaultShortcutCategoriesRepository
+import com.android.systemui.keyboard.shortcut.data.repository.InputGestureMaps
 import com.android.systemui.keyboard.shortcut.data.repository.ShortcutCategoriesUtils
 import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperStateRepository
 import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperTestHelper
@@ -54,10 +55,10 @@
     Kosmos.Fixture { AppCategoriesShortcutsSource(windowManager, testDispatcher) }
 
 var Kosmos.shortcutHelperSystemShortcutsSource: KeyboardShortcutGroupsSource by
-    Kosmos.Fixture { SystemShortcutsSource(mainResources) }
+    Kosmos.Fixture { SystemShortcutsSource(mainResources, fakeInputManager.inputManager) }
 
 var Kosmos.shortcutHelperMultiTaskingShortcutsSource: KeyboardShortcutGroupsSource by
-    Kosmos.Fixture { MultitaskingShortcutsSource(mainResources) }
+    Kosmos.Fixture { MultitaskingShortcutsSource(mainResources, applicationContext) }
 
 val Kosmos.shortcutHelperStateRepository by
     Kosmos.Fixture {
@@ -71,7 +72,9 @@
     }
 
 var Kosmos.shortcutHelperInputShortcutsSource: KeyboardShortcutGroupsSource by
-    Kosmos.Fixture { InputShortcutsSource(mainResources, windowManager) }
+    Kosmos.Fixture {
+        InputShortcutsSource(mainResources, windowManager, fakeInputManager.inputManager)
+    }
 
 var Kosmos.shortcutHelperCurrentAppShortcutsSource: KeyboardShortcutGroupsSource by
     Kosmos.Fixture { CurrentAppShortcutsSource(windowManager) }
@@ -101,6 +104,8 @@
         )
     }
 
+val Kosmos.inputGestureMaps by Kosmos.Fixture { InputGestureMaps(applicationContext) }
+
 val Kosmos.customShortcutCategoriesRepository by
     Kosmos.Fixture {
         CustomShortcutCategoriesRepository(
@@ -110,6 +115,7 @@
             testDispatcher,
             shortcutCategoriesUtils,
             applicationContext,
+            inputGestureMaps,
         )
     }
 
@@ -137,7 +143,10 @@
 
 val Kosmos.shortcutHelperCategoriesInteractor by
     Kosmos.Fixture {
-        ShortcutHelperCategoriesInteractor(defaultShortcutCategoriesRepository) {
+        ShortcutHelperCategoriesInteractor(
+            context = applicationContext,
+            defaultShortcutCategoriesRepository,
+        ) {
             customShortcutCategoriesRepository
         }
     }
@@ -173,7 +182,10 @@
     Kosmos.Fixture {
         object : ShortcutCustomizationViewModel.Factory {
             override fun create(): ShortcutCustomizationViewModel {
-                return ShortcutCustomizationViewModel(shortcutCustomizationInteractor)
+                return ShortcutCustomizationViewModel(
+                    applicationContext,
+                    shortcutCustomizationInteractor,
+                )
             }
         }
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
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
index bd841ab..09f5fd7 100644
--- 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
@@ -17,14 +17,12 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import com.android.keyguard.logging.KeyguardLogger
-import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
 import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
 import com.android.systemui.keyguard.data.repository.keyguardRepository
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.log.logcatLogBuffer
-import com.android.systemui.power.domain.interactor.powerInteractor
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.shade.domain.interactor.shadeInteractor
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -38,8 +36,6 @@
             dismissInteractor = keyguardDismissInteractor,
             applicationScope = testScope.backgroundScope,
             deviceUnlockedInteractor = { deviceUnlockedInteractor },
-            powerInteractor = powerInteractor,
-            alternateBouncerInteractor = alternateBouncerInteractor,
             shadeInteractor = { shadeInteractor },
             keyguardInteractor = { keyguardInteractor },
             sceneInteractor = { sceneInteractor },
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractorKosmos.kt
index 007d229..f88ed07 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractorKosmos.kt
@@ -16,18 +16,24 @@
 
 package com.android.systemui.keyguard.domain.interactor
 
+import com.android.internal.widget.lockPatternUtils
 import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.keyguardRepository
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.user.domain.interactor.selectedUserInteractor
 
 val Kosmos.keyguardEnabledInteractor by
     Kosmos.Fixture {
         KeyguardEnabledInteractor(
             applicationCoroutineScope,
+            testDispatcher,
             keyguardRepository,
             biometricSettingsRepository,
-            keyguardDismissTransitionInteractor,
+            selectedUserInteractor,
+            lockPatternUtils,
+            { keyguardDismissTransitionInteractor },
             internalTransitionInteractor = internalKeyguardTransitionInteractor,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLockWhileAwakeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLockWhileAwakeInteractorKosmos.kt
index 39236c7..2423949 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLockWhileAwakeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLockWhileAwakeInteractorKosmos.kt
@@ -24,5 +24,6 @@
         KeyguardLockWhileAwakeInteractor(
             biometricSettingsRepository = biometricSettingsRepository,
             keyguardEnabledInteractor = keyguardEnabledInteractor,
+            keyguardServiceLockNowInteractor = keyguardServiceLockNowInteractor,
         )
     }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardServiceLockNowInteractor.kt
similarity index 68%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardServiceLockNowInteractor.kt
index 7d3d8b9..29335c5 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardServiceLockNowInteractor.kt
@@ -13,10 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
-}
+package com.android.systemui.keyguard.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+
+val Kosmos.keyguardServiceLockNowInteractor by
+    Kosmos.Fixture { KeyguardServiceLockNowInteractor(backgroundScope = testScope) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorKosmos.kt
index 63e168d..4aa132c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorKosmos.kt
@@ -41,5 +41,7 @@
             lockPatternUtils,
             fakeSettings,
             selectedUserInteractor,
+            keyguardEnabledInteractor,
+            keyguardServiceLockNowInteractor,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
index b5e6f75..c0b39b1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
+import android.content.applicationContext
 import android.content.res.mainResources
 import com.android.systemui.common.ui.domain.interactor.configurationInteractor
 import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor
@@ -28,12 +29,13 @@
 val Kosmos.keyguardClockViewModel by
     Kosmos.Fixture {
         KeyguardClockViewModel(
+            context = applicationContext,
             keyguardClockInteractor = keyguardClockInteractor,
             applicationScope = applicationCoroutineScope,
             aodNotificationIconViewModel = notificationIconContainerAlwaysOnDisplayViewModel,
             shadeInteractor = shadeInteractor,
             systemBarUtils = systemBarUtilsProxy,
             configurationInteractor = configurationInteractor,
-            resources = mainResources
+            resources = mainResources,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelKosmos.kt
index a25b29fd..2311c0a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelKosmos.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor
 import com.android.systemui.shade.domain.interactor.shadeInteractor
 
 val Kosmos.lockscreenUserActionsViewModel by Fixture {
@@ -27,5 +28,6 @@
         deviceEntryInteractor = deviceEntryInteractor,
         communalInteractor = communalInteractor,
         shadeInteractor = shadeInteractor,
+        occlusionInteractor = sceneContainerOcclusionInteractor,
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt
index 72cb1df..1556058 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt
@@ -1,8 +1,12 @@
 package com.android.systemui.kosmos
 
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.FlowValue
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
 import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.settings.brightness.ui.BrightnessWarningToast
+import com.android.systemui.util.mockito.mock
 import kotlin.coroutines.CoroutineContext
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.test.StandardTestDispatcher
@@ -32,12 +36,15 @@
 fun Kosmos.useUnconfinedTestDispatcher() = apply { testDispatcher = UnconfinedTestDispatcher() }
 
 var Kosmos.testScope by Fixture { TestScope(testDispatcher) }
-var Kosmos.applicationCoroutineScope by Fixture { testScope.backgroundScope }
+var Kosmos.backgroundScope by Fixture { testScope.backgroundScope }
+var Kosmos.applicationCoroutineScope by Fixture { backgroundScope }
 var Kosmos.testCase: SysuiTestCase by Fixture()
 var Kosmos.backgroundCoroutineContext: CoroutineContext by Fixture {
-    testScope.backgroundScope.coroutineContext
+    backgroundScope.coroutineContext
 }
 var Kosmos.mainCoroutineContext: CoroutineContext by Fixture { testScope.coroutineContext }
+var Kosmos.brightnessWarningToast: BrightnessWarningToast by
+    Kosmos.Fixture { mock<BrightnessWarningToast>() }
 
 /**
  * Run this test body with a [Kosmos] as receiver, and using the [testScope] currently installed in
@@ -49,3 +56,5 @@
 fun Kosmos.runCurrent() = testScope.runCurrent()
 
 fun <T> Kosmos.collectLastValue(flow: Flow<T>) = testScope.collectLastValue(flow)
+
+fun <T> Kosmos.collectValues(flow: Flow<T>): FlowValue<List<T>> = testScope.collectValues(flow)
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 3d60abf..5b2c8dd 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
@@ -78,6 +78,7 @@
 import com.android.systemui.statusbar.notification.domain.interactor.seenNotificationsInteractor
 import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
 import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
+import com.android.systemui.statusbar.phone.fakeAutoHideControllerStore
 import com.android.systemui.statusbar.phone.keyguardBypassController
 import com.android.systemui.statusbar.phone.scrimController
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository
@@ -132,6 +133,7 @@
     val simBouncerInteractor by lazy { kosmos.simBouncerInteractor }
     val statusBarStateController by lazy { kosmos.statusBarStateController }
     val statusBarModePerDisplayRepository by lazy { kosmos.fakeStatusBarModePerDisplayRepository }
+    val autoHideControllerStore by lazy { kosmos.fakeAutoHideControllerStore }
     val interactionJankMonitor by lazy { kosmos.interactionJankMonitor }
     val fakeSceneContainerConfig by lazy { kosmos.sceneContainerConfig }
     val sceneInteractor by lazy { kosmos.sceneInteractor }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
index d631f92..e6256a5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.mediaprojection.data.repository
 
 import android.app.ActivityManager
+import android.media.projection.StopReason
 import com.android.systemui.mediaprojection.data.model.MediaProjectionState
 import kotlinx.coroutines.flow.MutableStateFlow
 
@@ -28,7 +29,7 @@
 
     var stopProjectingInvoked = false
 
-    override suspend fun stopProjecting() {
+    override suspend fun stopProjecting(@StopReason stopReason: Int) {
         stopProjectingInvoked = true
     }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSTile.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSTile.kt
index 562980d..06822a6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSTile.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSTile.kt
@@ -19,10 +19,12 @@
 import com.android.internal.logging.InstanceId
 import com.android.systemui.animation.Expandable
 import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.plugins.qs.TileDetailsViewModel
 
 class FakeQSTile(var user: Int, var available: Boolean = true) : QSTile {
     private var tileSpec: String? = null
     var destroyed = false
+    var hasDetailsViewModel: Boolean = true
     private var state = QSTile.State()
     val callbacks = mutableListOf<QSTile.Callback>()
 
@@ -91,6 +93,13 @@
         return false
     }
 
+    override fun getDetailsViewModel(): FakeTileDetailsViewModel? {
+        if (hasDetailsViewModel) {
+            return FakeTileDetailsViewModel(tileSpec)
+        }
+        return null
+    }
+
     fun changeState(newState: QSTile.State) {
         state = newState
         callbacks.forEach { it.onStateChanged(state) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeTileDetailsViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeTileDetailsViewModel.kt
new file mode 100644
index 0000000..555f019
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeTileDetailsViewModel.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.qs
+
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import com.android.systemui.plugins.qs.TileDetailsViewModel
+
+class FakeTileDetailsViewModel(var tileSpec: String?) : TileDetailsViewModel() {
+    private var _clickOnSettingsButton = 0
+
+    @Composable
+    override fun GetContentView() {
+        Text(
+            text = "Fake details content",
+            textAlign = TextAlign.Center,
+            fontWeight = FontWeight.ExtraBold,
+        )
+    }
+
+    override fun clickOnSettingsButton() {
+        _clickOnSettingsButton++
+    }
+
+    override fun getTitle(): String {
+        return tileSpec ?: " Fake title"
+    }
+
+    override fun getSubTitle(): String {
+        return tileSpec ?: "Fake sub title"
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt
index 45d5b38..c574463 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt
@@ -18,10 +18,12 @@
 
 import android.content.res.mainResources
 import androidx.lifecycle.LifecycleCoroutineScope
+import com.android.systemui.classifier.domain.interactor.falsingInteractor
 import com.android.systemui.common.ui.domain.interactor.configurationInteractor
 import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
 import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.log.table.logcatTableLogBuffer
 import com.android.systemui.media.controls.ui.view.qqsMediaHost
 import com.android.systemui.media.controls.ui.view.qsMediaHost
 import com.android.systemui.qs.composefragment.dagger.usingMediaInComposeFragment
@@ -57,7 +59,9 @@
                     configurationInteractor,
                     largeScreenHeaderHelper,
                     tileSquishinessInteractor,
+                    falsingInteractor,
                     inFirstPageViewModel,
+                    logcatTableLogBuffer(this@Fixture),
                     mediaInRowInLandscapeViewModelFactory,
                     qqsMediaHost,
                     qsMediaHost,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt
index b5a6bf1..6fe860c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt
@@ -19,12 +19,14 @@
 import com.android.systemui.haptics.msdl.tileHapticsViewModelFactoryProvider
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.InfiniteGridLayout
+import com.android.systemui.qs.panels.ui.viewmodel.detailsViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.iconTilesViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.infiniteGridViewModelFactory
 
 val Kosmos.infiniteGridLayout by
     Kosmos.Fixture {
         InfiniteGridLayout(
+            detailsViewModel,
             iconTilesViewModel,
             infiniteGridViewModelFactory,
             tileHapticsViewModelFactoryProvider,
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelKosmos.kt
similarity index 69%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelKosmos.kt
index 7d3d8b9..dc22905 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelKosmos.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
-}
+package com.android.systemui.qs.panels.ui.viewmodel
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor
+
+val Kosmos.detailsViewModel by Kosmos.Fixture { DetailsViewModel(currentTilesInteractor) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelKosmos.kt
new file mode 100644
index 0000000..b8d3ff4
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelKosmos.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.qs.panels.ui.viewmodel
+
+import com.android.systemui.classifier.domain.interactor.falsingInteractor
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.editModeButtonViewModelFactory by
+    Kosmos.Fixture {
+        object : EditModeButtonViewModel.Factory {
+            override fun create(): EditModeButtonViewModel {
+                return EditModeButtonViewModel(editModeViewModel, falsingInteractor)
+            }
+        }
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModelKosmos.kt
index 2e80293..5c71ba2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModelKosmos.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.panels.ui.viewmodel
 
+import com.android.systemui.classifier.domain.interactor.falsingInteractor
 import com.android.systemui.development.ui.viewmodel.buildNumberViewModelFactory
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.qs.panels.domain.interactor.paginatedGridInteractor
@@ -28,5 +29,7 @@
             paginatedGridInteractor,
             inFirstPageViewModel,
             buildNumberViewModelFactory,
+            editModeButtonViewModelFactory,
+            falsingInteractor,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelKosmos.kt
index ce103ec..6afc0d80 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelKosmos.kt
@@ -18,6 +18,7 @@
 
 import com.android.systemui.brightness.ui.viewmodel.brightnessSliderViewModelFactory
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.panels.ui.viewmodel.detailsViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.editModeViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.quickQuickSettingsViewModelFactory
 import com.android.systemui.qs.panels.ui.viewmodel.tileGridViewModel
@@ -34,6 +35,7 @@
                     supportsBrightnessMirroring,
                     tileGridViewModel,
                     editModeViewModel,
+                    detailsViewModel,
                 )
             }
         }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
index 3300c96..0eca818 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
@@ -13,6 +13,7 @@
 import com.android.systemui.scene.shared.model.SceneContainerConfig
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.ui.FakeOverlay
+import com.android.systemui.scene.ui.composable.SceneContainerTransitions
 import com.android.systemui.scene.ui.viewmodel.SceneContainerHapticsViewModel
 import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
 import com.android.systemui.scene.ui.viewmodel.splitEdgeDetector
@@ -60,6 +61,7 @@
     SceneContainerConfig(
         sceneKeys = sceneKeys,
         initialSceneKey = initialSceneKey,
+        transitions = SceneContainerTransitions,
         overlayKeys = overlayKeys,
         navigationDistances = navigationDistances,
     )
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/HeadsUpManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractorKosmos.kt
similarity index 66%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/HeadsUpManagerKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractorKosmos.kt
index a4db00c..12d4e90 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/HeadsUpManagerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/DisabledContentInteractorKosmos.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.policy
+package com.android.systemui.scene.domain.interactor
 
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor
 
-var Kosmos.headsUpManager by Fixture { mock<HeadsUpManager>() }
+val Kosmos.disabledContentInteractor by Fixture {
+    DisabledContentInteractor(disableFlagsInteractor = disableFlagsInteractor)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt
index f84c3bd..eb352ba 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt
@@ -33,5 +33,6 @@
             sceneFamilyResolvers = { sceneFamilyResolvers },
             deviceUnlockedInteractor = { deviceUnlockedInteractor },
             keyguardEnabledInteractor = { keyguardEnabledInteractor },
+            disabledContentInteractor = disabledContentInteractor,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt
index 7e6a727..82b5f63 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt
@@ -37,6 +37,7 @@
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.model.sysUiState
 import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.scene.domain.interactor.disabledContentInteractor
 import com.android.systemui.scene.domain.interactor.sceneBackInteractor
 import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor
 import com.android.systemui.scene.domain.interactor.sceneInteractor
@@ -83,5 +84,6 @@
         alternateBouncerInteractor = alternateBouncerInteractor,
         vibratorHelper = vibratorHelper,
         msdlPlayer = msdlPlayer,
+        disabledContentInteractor = disabledContentInteractor,
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt
new file mode 100644
index 0000000..dbaa0b1
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.shade.data.repository
+
+import android.view.Display
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.shade.display.ShadeDisplayPolicy
+import com.android.systemui.shade.display.SpecificDisplayIdPolicy
+
+val Kosmos.defaultShadeDisplayPolicy: ShadeDisplayPolicy by
+    Kosmos.Fixture { SpecificDisplayIdPolicy(Display.DEFAULT_DISPLAY) }
+
+val Kosmos.shadeDisplaysRepository: MutableShadeDisplaysRepository by
+    Kosmos.Fixture {
+        ShadeDisplaysRepositoryImpl(
+            defaultPolicy = defaultShadeDisplayPolicy,
+            bgScope = testScope.backgroundScope,
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModelKosmos.kt
index 7097d31..694bb6e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModelKosmos.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.settings.brightness.ui.viewmodel.brightnessMirrorViewModelFactory
 import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor
 import com.android.systemui.unfold.domain.interactor.unfoldTransitionInteractor
 
 val Kosmos.shadeSceneContentViewModel: ShadeSceneContentViewModel by Fixture {
@@ -35,6 +36,7 @@
         brightnessMirrorViewModelFactory = brightnessMirrorViewModelFactory,
         mediaCarouselInteractor = mediaCarouselInteractor,
         shadeInteractor = shadeInteractor,
+        disableFlagsInteractor = disableFlagsInteractor,
         footerActionsViewModelFactory = footerActionsViewModelFactory,
         footerActionsController = footerActionsController,
         unfoldTransitionInteractor = unfoldTransitionInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorFactoryKosmos.kt
new file mode 100644
index 0000000..1c095e1
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorFactoryKosmos.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.statusbar.chips.notification.domain.interactor
+
+import com.android.systemui.activity.data.repository.activityManagerRepository
+import com.android.systemui.activity.data.repository.fake
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.chips.statusBarChipsLogger
+
+val Kosmos.singleNotificationChipInteractorFactory: SingleNotificationChipInteractor.Factory by
+    Kosmos.Fixture {
+        SingleNotificationChipInteractor.Factory { startingModel ->
+            SingleNotificationChipInteractor(
+                startingModel,
+                activityManagerRepository.fake,
+                logBuffer = statusBarChipsLogger,
+            )
+        }
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorKosmos.kt
index 74c7611..03e9f3d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorKosmos.kt
@@ -17,6 +17,16 @@
 package com.android.systemui.statusbar.chips.notification.domain.interactor
 
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.chips.statusBarChipsLogger
+import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
 
 val Kosmos.statusBarNotificationChipsInteractor: StatusBarNotificationChipsInteractor by
-    Kosmos.Fixture { StatusBarNotificationChipsInteractor() }
+    Kosmos.Fixture {
+        StatusBarNotificationChipsInteractor(
+            testScope.backgroundScope,
+            activeNotificationsInteractor,
+            singleNotificationChipInteractorFactory,
+            logBuffer = statusBarChipsLogger,
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelKosmos.kt
index 68b28ad..4bcce86 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelKosmos.kt
@@ -19,13 +19,8 @@
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor
-import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
 
 val Kosmos.notifChipsViewModel: NotifChipsViewModel by
     Kosmos.Fixture {
-        NotifChipsViewModel(
-            applicationCoroutineScope,
-            activeNotificationsInteractor,
-            statusBarNotificationChipsInteractor,
-        )
+        NotifChipsViewModel(applicationCoroutineScope, statusBarNotificationChipsInteractor)
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarOrchestratorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarOrchestratorFactory.kt
index 9197dcd..2d88ae8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarOrchestratorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarOrchestratorFactory.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.core
 
 import com.android.systemui.statusbar.data.repository.StatusBarModePerDisplayRepository
+import com.android.systemui.statusbar.phone.AutoHideController
 import com.android.systemui.statusbar.window.StatusBarWindowController
 import com.android.systemui.statusbar.window.data.repository.StatusBarWindowStatePerDisplayRepository
 import kotlinx.coroutines.CoroutineScope
@@ -36,6 +37,7 @@
         statusBarModeRepository: StatusBarModePerDisplayRepository,
         statusBarInitializer: StatusBarInitializer,
         statusBarWindowController: StatusBarWindowController,
+        autoHideController: AutoHideController,
     ): StatusBarOrchestrator =
         mock<StatusBarOrchestrator>().also { createdOrchestrators[displayId] = it }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarOrchestratorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarOrchestratorKosmos.kt
index 28edae7..8c37bd7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarOrchestratorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarOrchestratorKosmos.kt
@@ -34,6 +34,7 @@
 import com.android.systemui.statusbar.data.repository.statusBarModeRepository
 import com.android.systemui.statusbar.mockNotificationRemoteInputManager
 import com.android.systemui.statusbar.phone.mockAutoHideController
+import com.android.systemui.statusbar.phone.multiDisplayAutoHideControllerStore
 import com.android.systemui.statusbar.window.data.repository.fakeStatusBarWindowStatePerDisplayRepository
 import com.android.systemui.statusbar.window.data.repository.statusBarWindowStateRepositoryStore
 import com.android.systemui.statusbar.window.fakeStatusBarWindowController
@@ -50,9 +51,9 @@
             fakeStatusBarInitializer,
             fakeStatusBarWindowController,
             applicationCoroutineScope.coroutineContext,
+            mockAutoHideController,
             mockDemoModeController,
             mockPluginDependencyProvider,
-            mockAutoHideController,
             mockNotificationRemoteInputManager,
             { mockNotificationShadeWindowViewController },
             mockShadeSurface,
@@ -80,6 +81,7 @@
             statusBarInitializerStore,
             statusBarWindowControllerStore,
             statusBarInitializerStore,
+            multiDisplayAutoHideControllerStore,
             privacyDotWindowControllerStore,
             lightBarControllerStore,
         )
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/FakeHeadsUpRowRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/FakeHeadsUpRowRepository.kt
index 980d65f..7de22d8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/FakeHeadsUpRowRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/FakeHeadsUpRowRepository.kt
@@ -16,13 +16,27 @@
 
 package com.android.systemui.statusbar.notification.data.repository
 
+import com.android.systemui.statusbar.notification.headsup.PinnedStatus
 import kotlinx.coroutines.flow.MutableStateFlow
 
 class FakeHeadsUpRowRepository(override val key: String, override val elementKey: Any = Any()) :
     HeadsUpRowRepository {
-    constructor(key: String, isPinned: Boolean) : this(key = key) {
-        this.isPinned.value = isPinned
+    constructor(
+        key: String,
+        elementKey: Any = Any(),
+        isPinned: Boolean,
+    ) : this(key = key, elementKey = elementKey) {
+        this.pinnedStatus.value = if (isPinned) PinnedStatus.PinnedBySystem else PinnedStatus.NotPinned
     }
 
-    override val isPinned: MutableStateFlow<Boolean> = MutableStateFlow(false)
+    constructor(
+        key: String,
+        elementKey: Any = Any(),
+        pinnedStatus: PinnedStatus,
+    ) : this(key = key, elementKey = elementKey) {
+        this.pinnedStatus.value = pinnedStatus
+    }
+
+    override val pinnedStatus: MutableStateFlow<PinnedStatus> =
+        MutableStateFlow(PinnedStatus.NotPinned)
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/HeadsUpManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerKosmos.kt
similarity index 92%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/HeadsUpManagerKosmos.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerKosmos.kt
index a4db00c..de9485d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/HeadsUpManagerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerKosmos.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.policy
+package com.android.systemui.statusbar.notification.headsup
 
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/FakePromotedNotificationsProvider.kt
similarity index 60%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/FakePromotedNotificationsProvider.kt
index 7d3d8b9..88caf6e 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/FakePromotedNotificationsProvider.kt
@@ -13,10 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
+package com.android.systemui.statusbar.notification.promoted
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+
+class FakePromotedNotificationsProvider : PromotedNotificationsProvider {
+    val promotedEntries = mutableSetOf<NotificationEntry>()
+
+    override fun shouldPromote(entry: NotificationEntry): Boolean {
+        return promotedEntries.contains(entry)
     }
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt
similarity index 61%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt
index 7d3d8b9..5e9f12b 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt
@@ -13,10 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
+package com.android.systemui.statusbar.notification.promoted
+
+import android.content.applicationContext
+import com.android.systemui.kosmos.Kosmos
+
+var Kosmos.promotedNotificationContentExtractor by
+    Kosmos.Fixture {
+        PromotedNotificationContentExtractor(
+            promotedNotificationsProvider,
+            applicationContext,
+            promotedNotificationLogger,
+        )
     }
-}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLoggerKosmos.kt
similarity index 68%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLoggerKosmos.kt
index 7d3d8b9..2805d1e 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLoggerKosmos.kt
@@ -13,10 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
-}
+package com.android.systemui.statusbar.notification.promoted
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.log.logcatLogBuffer
+
+val Kosmos.promotedNotificationLogger by
+    Kosmos.Fixture { PromotedNotificationLogger(logcatLogBuffer("PromotedNotifLog")) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationsProviderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationsProviderKosmos.kt
index a7aa0b4..580f617 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationsProviderKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationsProviderKosmos.kt
@@ -18,4 +18,5 @@
 
 import com.android.systemui.kosmos.Kosmos
 
-val Kosmos.promotedNotificationsProvider by Kosmos.Fixture { PromotedNotificationsProviderImpl() }
+var Kosmos.promotedNotificationsProvider: PromotedNotificationsProvider by
+    Kosmos.Fixture { PromotedNotificationsProviderImpl() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
index 31d3908..2d3f68f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.flags.FakeFeatureFlagsClassic
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
+import com.android.systemui.log.logcatLogBuffer
 import com.android.systemui.media.controls.util.MediaFeatureFlag
 import com.android.systemui.media.dialog.MediaOutputDialogManager
 import com.android.systemui.plugins.ActivityStarter
@@ -60,9 +61,13 @@
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.notification.icon.IconBuilder
 import com.android.systemui.statusbar.notification.icon.IconManager
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationLogger
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationsProviderImpl
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.CoordinateOnClickListener
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.ExpandableNotificationRowLogger
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.OnExpandClickListener
@@ -77,7 +82,6 @@
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.SmartActionInflaterImpl
 import com.android.systemui.statusbar.policy.SmartReplyConstants
 import com.android.systemui.statusbar.policy.SmartReplyInflaterImpl
@@ -221,6 +225,17 @@
                 Mockito.mock(ConversationNotificationManager::class.java, STUB_ONLY),
             )
 
+        val promotedNotificationsProvider = PromotedNotificationsProviderImpl()
+        val promotedNotificationLog = logcatLogBuffer("PromotedNotifLog")
+        val promotedNotificationLogger = PromotedNotificationLogger(promotedNotificationLog)
+
+        val promotedNotificationContentExtractor =
+            PromotedNotificationContentExtractor(
+                promotedNotificationsProvider,
+                context,
+                promotedNotificationLogger,
+            )
+
         mContentBinder =
             if (NotificationRowContentBinderRefactor.isEnabled)
                 NotificationRowContentBinderImpl(
@@ -231,6 +246,7 @@
                     smartReplyStateInflater,
                     notifLayoutInflaterFactoryProvider,
                     Mockito.mock(HeadsUpStyleProvider::class.java, STUB_ONLY),
+                    promotedNotificationContentExtractor,
                     Mockito.mock(NotificationRowContentBinderLogger::class.java, STUB_ONLY),
                 )
             else
@@ -243,6 +259,7 @@
                     smartReplyStateInflater,
                     notifLayoutInflaterFactoryProvider,
                     Mockito.mock(HeadsUpStyleProvider::class.java, STUB_ONLY),
+                    promotedNotificationContentExtractor,
                     Mockito.mock(NotificationRowContentBinderLogger::class.java, STUB_ONLY),
                 )
         mContentBinder.setInflateSynchronously(true)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/OnUserInteractionCallbackKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/OnUserInteractionCallbackKosmos.kt
index 1e3897b..ec54c33 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/OnUserInteractionCallbackKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/OnUserInteractionCallbackKosmos.kt
@@ -22,7 +22,7 @@
 import com.android.systemui.statusbar.notification.collection.inflation.OnUserInteractionCallbackImpl
 import com.android.systemui.statusbar.notification.collection.notifCollection
 import com.android.systemui.statusbar.notification.collection.render.notificationVisibilityProvider
-import com.android.systemui.statusbar.policy.headsUpManager
+import com.android.systemui.statusbar.notification.headsup.headsUpManager
 
 var Kosmos.onUserInteractionCallback: OnUserInteractionCallback by
     Kosmos.Fixture {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmKosmos.kt
index e20ce27..a5c4bfd 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmKosmos.kt
@@ -18,7 +18,7 @@
 
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
-import com.android.systemui.statusbar.policy.AvalancheController
+import com.android.systemui.statusbar.notification.headsup.AvalancheController
 import com.android.systemui.util.mockito.mock
 
 var Kosmos.stackScrollAlgorithmSectionProvider by Fixture {
@@ -29,6 +29,4 @@
     mock<StackScrollAlgorithm.BypassController>()
 }
 
-var Kosmos.avalancheController by Fixture {
-    mock<AvalancheController>()
-}
+var Kosmos.avalancheController by Fixture { mock<AvalancheController>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
index 7fbf4e4..d1619b7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
 import com.android.systemui.keyguard.ui.viewmodel.alternateBouncerToGoneTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.alternateBouncerToPrimaryBouncerTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.aodBurnInViewModel
 import com.android.systemui.keyguard.ui.viewmodel.aodToGoneTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.aodToLockscreenTransitionViewModel
@@ -71,6 +72,8 @@
         shadeInteractor = shadeInteractor,
         notificationStackAppearanceInteractor = notificationStackAppearanceInteractor,
         alternateBouncerToGoneTransitionViewModel = alternateBouncerToGoneTransitionViewModel,
+        alternateBouncerToPrimaryBouncerTransitionViewModel =
+            alternateBouncerToPrimaryBouncerTransitionViewModel,
         aodToGoneTransitionViewModel = aodToGoneTransitionViewModel,
         aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel,
         aodToOccludedTransitionViewModel = aodToOccludedTransitionViewModel,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/WindowRootViewVisibilityInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/WindowRootViewVisibilityInteractorKosmos.kt
index 9c3f510..e972c2c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/WindowRootViewVisibilityInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/WindowRootViewVisibilityInteractorKosmos.kt
@@ -25,7 +25,7 @@
 import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
-import com.android.systemui.statusbar.policy.headsUpManager
+import com.android.systemui.statusbar.notification.headsup.headsUpManager
 
 val Kosmos.windowRootViewVisibilityInteractor by Fixture {
     WindowRootViewVisibilityInteractor(
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/AutoHideKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/AutoHideKosmos.kt
index 090ce31..b99e93a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/AutoHideKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/AutoHideKosmos.kt
@@ -16,9 +16,49 @@
 
 package com.android.systemui.statusbar.phone
 
+import android.content.Context
+import android.os.Handler
+import android.view.Display
+import android.view.IWindowManager
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.display.data.repository.fakeDisplayWindowPropertiesRepository
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.kosmos.applicationCoroutineScope
+import org.mockito.Mockito.mock
 
-val Kosmos.mockAutoHideController by Kosmos.Fixture { mock<AutoHideController>() }
+val Kosmos.mockAutoHideController: AutoHideController by
+    Kosmos.Fixture { mock(AutoHideController::class.java) }
 
-var Kosmos.autoHideController by Kosmos.Fixture { mockAutoHideController }
+val Kosmos.fakeAutoHideControllerFactory by Kosmos.Fixture { FakeAutoHideControllerFactory() }
+
+val Kosmos.multiDisplayAutoHideControllerStore by
+    Kosmos.Fixture {
+        MultiDisplayAutoHideControllerStore(
+            applicationCoroutineScope,
+            displayRepository,
+            fakeDisplayWindowPropertiesRepository,
+            fakeAutoHideControllerFactory,
+        )
+    }
+
+val Kosmos.fakeAutoHideControllerStore by Kosmos.Fixture { FakeAutoHideControllerStore() }
+
+class FakeAutoHideControllerFactory :
+    AutoHideControllerImpl.Factory(mock(Handler::class.java), mock(IWindowManager::class.java)) {
+
+    override fun create(context: Context): AutoHideControllerImpl {
+        return mock(AutoHideControllerImpl::class.java)
+    }
+}
+
+class FakeAutoHideControllerStore : AutoHideControllerStore {
+
+    private val perDisplayMocks = mutableMapOf<Int, AutoHideController>()
+
+    override val defaultDisplay: AutoHideController
+        get() = forDisplay(Display.DEFAULT_DISPLAY)
+
+    override fun forDisplay(displayId: Int): AutoHideController {
+        return perDisplayMocks.computeIfAbsent(displayId) { mock(AutoHideController::class.java) }
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeServiceHostKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeServiceHostKosmos.kt
index 4a6757d..f86824a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeServiceHostKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeServiceHostKosmos.kt
@@ -26,10 +26,10 @@
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.plugins.statusbar.statusBarStateController
 import com.android.systemui.shade.domain.interactor.shadeLockscreenInteractor
+import com.android.systemui.statusbar.notification.headsup.headsUpManager
 import com.android.systemui.statusbar.notificationShadeWindowController
 import com.android.systemui.statusbar.policy.batteryController
 import com.android.systemui.statusbar.policy.deviceProvisionedController
-import com.android.systemui.statusbar.policy.headsUpManager
 import com.android.systemui.statusbar.pulseExpansionHandler
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ShadeTouchableRegionManagerKosmos.kt
similarity index 91%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerKosmos.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ShadeTouchableRegionManagerKosmos.kt
index 87ea147..5b7f23b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ShadeTouchableRegionManagerKosmos.kt
@@ -24,16 +24,15 @@
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.statusbar.notification.headsup.headsUpManager
 import com.android.systemui.statusbar.notificationShadeWindowController
 import com.android.systemui.statusbar.policy.configurationController
-import com.android.systemui.statusbar.policy.headsUpManager
 import com.android.systemui.util.kotlin.JavaAdapter
 import com.android.systemui.util.mockito.mock
-import org.mockito.Mockito.mock
 
-var Kosmos.statusBarTouchableRegionManager by
+var Kosmos.shadeTouchableRegionManager by
     Kosmos.Fixture {
-        StatusBarTouchableRegionManager(
+        ShadeTouchableRegionManager(
             applicationContext,
             notificationShadeWindowController,
             configurationController,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt
index c6684af..6083414 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.statusbar.commandQueue
 import com.android.systemui.statusbar.notification.collection.provider.launchFullScreenIntentProvider
 import com.android.systemui.statusbar.notification.collection.render.notificationVisibilityProvider
+import com.android.systemui.statusbar.notification.headsup.headsUpManager
 import com.android.systemui.statusbar.notification.notificationTransitionAnimatorControllerProvider
 import com.android.systemui.statusbar.notification.row.onUserInteractionCallback
 import com.android.systemui.statusbar.notificationClickNotifier
@@ -43,7 +44,6 @@
 import com.android.systemui.statusbar.notificationPresenter
 import com.android.systemui.statusbar.notificationRemoteInputManager
 import com.android.systemui.statusbar.notificationShadeWindowController
-import com.android.systemui.statusbar.policy.headsUpManager
 import com.android.systemui.statusbar.policy.keyguardStateController
 import com.android.systemui.wmshell.bubblesManager
 import java.util.Optional
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
index 03e4c89..eb17237 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
 import com.android.systemui.statusbar.events.domain.interactor.systemStatusEventAnimationInteractor
 import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
+import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
 import com.android.systemui.statusbar.phone.domain.interactor.lightsOutInteractor
 import com.android.systemui.statusbar.pipeline.shared.domain.interactor.collapsedStatusBarInteractor
 
@@ -35,6 +36,7 @@
             collapsedStatusBarInteractor,
             lightsOutInteractor,
             activeNotificationsInteractor,
+            headsUpNotificationInteractor,
             keyguardTransitionInteractor,
             keyguardInteractor,
             sceneInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/ui/gesture/FakeVelocityTracker.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/ui/gesture/FakeVelocityTracker.kt
new file mode 100644
index 0000000..f12089a
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/ui/gesture/FakeVelocityTracker.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.touchpad.ui.gesture
+
+import android.view.MotionEvent
+import com.android.systemui.touchpad.tutorial.ui.gesture.Velocity
+import com.android.systemui.touchpad.tutorial.ui.gesture.VelocityTracker
+
+class FakeVelocityTracker : VelocityTracker {
+
+    private var fakeVelocity = Velocity(0f)
+
+    override fun calculateVelocity(): Velocity {
+        return fakeVelocity
+    }
+
+    override fun accept(event: MotionEvent) {}
+
+    fun setVelocity(velocity: Velocity) {
+        fakeVelocity = velocity
+    }
+}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/ui/gesture/VelocityTrackerKosmos.kt
similarity index 73%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/ui/gesture/VelocityTrackerKosmos.kt
index 7d3d8b9..3b61e21 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/ui/gesture/VelocityTrackerKosmos.kt
@@ -13,10 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
-}
+package com.android.systemui.touchpad.ui.gesture
+
+import com.android.systemui.kosmos.Kosmos
+
+var Kosmos.fakeVelocityTracker: FakeVelocityTracker by Kosmos.Fixture { FakeVelocityTracker() }
diff --git a/packages/Vcn/service-b/Android.bp b/packages/Vcn/service-b/Android.bp
index a462297..03ef4e6 100644
--- a/packages/Vcn/service-b/Android.bp
+++ b/packages/Vcn/service-b/Android.bp
@@ -19,6 +19,19 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
+filegroup {
+    name: "vcn-location-sources",
+    srcs: select(release_flag("RELEASE_MOVE_VCN_TO_MAINLINE"), {
+        true: [
+            "vcn-location-flag/module/com/android/server/vcn/VcnLocation.java",
+        ],
+        default: [
+            "vcn-location-flag/platform/com/android/server/vcn/VcnLocation.java",
+        ],
+    }),
+    visibility: ["//frameworks/base/services/core"],
+}
+
 java_library {
     name: "service-connectivity-b-pre-jarjar",
     sdk_version: "system_server_current",
diff --git a/packages/Vcn/service-b/vcn-location-flag/module/com/android/server/vcn/VcnLocation.java b/packages/Vcn/service-b/vcn-location-flag/module/com/android/server/vcn/VcnLocation.java
new file mode 100644
index 0000000..6c7d24d
--- /dev/null
+++ b/packages/Vcn/service-b/vcn-location-flag/module/com/android/server/vcn/VcnLocation.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+/**
+ * Class to represent that VCN is in a mainline module
+ *
+ * <p>This class is used to check whether VCN is in the non-updatable platform or in a mainline
+ * module.
+ */
+// When VCN is in a mainline module, this class (module/com/android/server/vcn/VcnLocation.java)
+// will be built in to the vcn-location-sources filegroup. When VCN is in the non-updatable
+// platform, platform/com/android/server/vcn/VcnLocation.java will be built in to the filegroup
+public class VcnLocation {
+    /** Indicate that VCN is the platform */
+    public static final boolean IS_VCN_IN_MAINLINE = true;
+}
diff --git a/packages/Vcn/service-b/vcn-location-flag/platform/com/android/server/vcn/VcnLocation.java b/packages/Vcn/service-b/vcn-location-flag/platform/com/android/server/vcn/VcnLocation.java
new file mode 100644
index 0000000..c6c82a5
--- /dev/null
+++ b/packages/Vcn/service-b/vcn-location-flag/platform/com/android/server/vcn/VcnLocation.java
@@ -0,0 +1,32 @@
+/*
+ * 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.vcn;
+
+/**
+ * Class to represent that VCN is in the platform
+ *
+ * <p>This class is used to check whether VCN is in the non-updatable platform or in a mainline
+ * module.
+ */
+// When VCN is in a mainline module, module/com/android/server/vcn/VcnLocation.java
+// will be built in to the vcn-location-sources filegroup. When VCN is in the non-updatable
+// platform, this class (platform/com/android/server/vcn/VcnLocation.java) will be built in to the
+// filegroup
+public class VcnLocation {
+    /** Indicate that VCN is the platform */
+    public static final boolean IS_VCN_IN_MAINLINE = false;
+}
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 0c2ce8d..66c8d0f 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -282,20 +282,12 @@
     visibility: ["//visibility:private"],
 }
 
-cc_library_host_shared {
-    name: "libravenwood_initializer",
-    defaults: ["ravenwood_jni_defaults"],
-    srcs: [
-        "runtime-jni/ravenwood_initializer.cpp",
-    ],
-}
-
 // We need this as a separate library because we need to overload the
 // sysprop symbols before libbase is loaded into the process
 cc_library_host_shared {
-    name: "libravenwood_sysprop",
+    name: "libravenwood_initializer",
     defaults: ["ravenwood_jni_defaults"],
-    srcs: ["runtime-jni/ravenwood_sysprop.cpp"],
+    srcs: ["runtime-jni/ravenwood_initializer.cpp"],
 }
 
 cc_library_host_shared {
@@ -669,7 +661,6 @@
     jni_libs: [
         // Libraries has to be loaded in the following order
         "libravenwood_initializer",
-        "libravenwood_sysprop",
         "libravenwood_runtime",
         "libandroid_runtime",
     ],
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
index 9b71f80..de3c5f2 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
@@ -133,9 +133,6 @@
 
         Log.v(TAG, "RavenwoodAwareTestRunner starting for " + testClass.getCanonicalName());
 
-        // This is needed to make AndroidJUnit4ClassRunner happy.
-        InstrumentationRegistry.registerInstance(null, Bundle.EMPTY);
-
         // Hook point to allow more customization.
         runAnnotatedMethodsOnRavenwood(RavenwoodTestRunnerInitializing.class, null);
 
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodConfigState.java
deleted file mode 100644
index 870a10a..0000000
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ /dev/null
@@ -1,85 +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 android.platform.test.ravenwood;
-
-import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_EMPTY_RESOURCES_APK;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.annotation.Nullable;
-import android.app.ResourcesManager;
-import android.content.res.Resources;
-import android.view.DisplayAdjustments;
-
-import java.io.File;
-import java.util.HashMap;
-
-/**
- * Used to store various states associated with {@link RavenwoodConfig} that's inly needed
- * in junit-impl.
- *
- * We don't want to put it in junit-src to avoid having to recompile all the downstream
- * dependencies after changing this class.
- *
- * All members must be called from the runner's main thread.
- */
-public class RavenwoodConfigState {
-    private static final String TAG = "RavenwoodConfigState";
-
-    private final RavenwoodConfig mConfig;
-
-    // TODO: Move the other contexts from RavenwoodConfig to here too? They're used by
-    // RavenwoodRule too, but RavenwoodRule can probably use InstrumentationRegistry?
-    RavenwoodContext mSystemServerContext;
-
-    public RavenwoodConfigState(RavenwoodConfig config) {
-        mConfig = config;
-    }
-
-    /** Map from path -> resources. */
-    private final HashMap<File, Resources> mCachedResources = new HashMap<>();
-
-    /**
-     * Load {@link Resources} from an APK, with cache.
-     */
-    public Resources loadResources(@Nullable File apkPath) {
-        var cached = mCachedResources.get(apkPath);
-        if (cached != null) {
-            return cached;
-        }
-
-        var fileToLoad = apkPath != null ? apkPath : new File(RAVENWOOD_EMPTY_RESOURCES_APK);
-
-        assertTrue("File " + fileToLoad + " doesn't exist.", fileToLoad.isFile());
-
-        final String path = fileToLoad.getAbsolutePath();
-        final var emptyPaths = new String[0];
-
-        ResourcesManager.getInstance().initializeApplicationPaths(path, emptyPaths);
-
-        final var ret = ResourcesManager.getInstance().getResources(null, path,
-                emptyPaths, emptyPaths, emptyPaths,
-                emptyPaths, null, null,
-                new DisplayAdjustments().getCompatibilityInfo(),
-                RavenwoodRuntimeEnvironmentController.class.getClassLoader(), null);
-
-        assertNotNull(ret);
-
-        mCachedResources.put(apkPath, ret);
-        return ret;
-    }
-}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
index ec00e8f..6dfcf4ce 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
@@ -15,24 +15,23 @@
  */
 package android.platform.test.ravenwood;
 
-import static com.android.ravenwood.common.RavenwoodCommonUtils.ensureIsPublicMember;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
-import static org.junit.Assert.fail;
-
-import android.annotation.Nullable;
 import android.util.Log;
+import android.util.Pair;
 
-import com.android.ravenwood.common.RavenwoodRuntimeException;
+import com.android.ravenwood.RavenwoodRuntimeNative;
 
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 
-import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
 
 /**
- * Used to store various states associated with the current test runner that's inly needed
+ * Used to store various states associated with the current test runner that's only needed
  * in junit-impl.
  *
  * We don't want to put it in junit-src to avoid having to recompile all the downstream
@@ -42,6 +41,11 @@
  */
 public final class RavenwoodRunnerState {
     private static final String TAG = "RavenwoodRunnerState";
+    private static final String RAVENWOOD_RULE_ERROR =
+            "RavenwoodRule(s) are not executed in the correct order";
+
+    private static final List<Pair<RavenwoodRule, RavenwoodPropertyState>> sActiveProperties =
+            new ArrayList<>();
 
     private final RavenwoodAwareTestRunner mRunner;
 
@@ -52,207 +56,95 @@
         mRunner = runner;
     }
 
-    /**
-     * The RavenwoodConfig used to configure the current Ravenwood environment.
-     * This can either come from mConfig or mRule.
-     */
-    private RavenwoodConfig mCurrentConfig;
-    /**
-     * The RavenwoodConfig declared in the test class
-     */
-    private RavenwoodConfig mConfig;
-    /**
-     * The RavenwoodRule currently in effect, declared in the test class
-     */
-    private RavenwoodRule mRule;
-    private boolean mHasRavenwoodRule;
     private Description mMethodDescription;
 
-    public RavenwoodConfig getConfig() {
-        return mCurrentConfig;
-    }
-
     public void enterTestRunner() {
         Log.i(TAG, "enterTestRunner: " + mRunner);
-
-        mHasRavenwoodRule = hasRavenwoodRule(mRunner.mTestJavaClass);
-        mConfig = extractConfiguration(mRunner.mTestJavaClass);
-
-        if (mConfig != null) {
-            if (mHasRavenwoodRule) {
-                fail("RavenwoodConfig and RavenwoodRule cannot be used in the same class."
-                        + " Suggest migrating to RavenwoodConfig.");
-            }
-            mCurrentConfig = mConfig;
-        } else if (!mHasRavenwoodRule) {
-            // If no RavenwoodConfig and no RavenwoodRule, use a default config
-            mCurrentConfig = new RavenwoodConfig.Builder().build();
-        }
-
-        if (mCurrentConfig != null) {
-            RavenwoodRuntimeEnvironmentController.init(mRunner);
-        }
+        RavenwoodRuntimeEnvironmentController.initForRunner();
     }
 
     public void enterTestClass() {
         Log.i(TAG, "enterTestClass: " + mRunner.mTestJavaClass.getName());
-
-        if (mCurrentConfig != null) {
-            RavenwoodRuntimeEnvironmentController.init(mRunner);
-        }
     }
 
     public void exitTestClass() {
         Log.i(TAG, "exitTestClass: " + mRunner.mTestJavaClass.getName());
-        try {
-            if (mCurrentConfig != null) {
-                RavenwoodRuntimeEnvironmentController.reset();
-            }
-        } finally {
-            mConfig = null;
-            mRule = null;
-        }
+        assertTrue(RAVENWOOD_RULE_ERROR, sActiveProperties.isEmpty());
+        RavenwoodRuntimeEnvironmentController.exitTestClass();
     }
 
     public void enterTestMethod(Description description) {
         mMethodDescription = description;
+        RavenwoodRuntimeEnvironmentController.initForMethod();
     }
 
     public void exitTestMethod() {
         mMethodDescription = null;
-        RavenwoodRuntimeEnvironmentController.reinit();
     }
 
     public void enterRavenwoodRule(RavenwoodRule rule) {
-        if (!mHasRavenwoodRule) {
-            fail("If you have a RavenwoodRule in your test, make sure the field type is"
-                    + " RavenwoodRule so Ravenwood can detect it.");
-        }
-        if (mRule != null) {
-            fail("Multiple nesting RavenwoodRule's are detected in the same class,"
-                    + " which is not supported.");
-        }
-        mRule = rule;
-        if (mCurrentConfig == null) {
-            mCurrentConfig = rule.getConfiguration();
-        }
-        RavenwoodRuntimeEnvironmentController.init(mRunner);
+        pushTestProperties(rule);
     }
 
     public void exitRavenwoodRule(RavenwoodRule rule) {
-        if (mRule != rule) {
-            fail("RavenwoodRule did not take effect.");
-        }
-        mRule = null;
+        popTestProperties(rule);
     }
 
-    /**
-     * @return a configuration from a test class, if any.
-     */
-    @Nullable
-    private static RavenwoodConfig extractConfiguration(Class<?> testClass) {
-        var field = findConfigurationField(testClass);
-        if (field == null) {
-            return null;
+    static class RavenwoodPropertyState {
+
+        final List<Pair<String, String>> mBackup;
+        final Set<String> mKeyReadable;
+        final Set<String> mKeyWritable;
+
+        RavenwoodPropertyState(RavenwoodTestProperties props) {
+            mBackup = props.mValues.keySet().stream()
+                    .map(key -> Pair.create(key, RavenwoodRuntimeNative.getSystemProperty(key)))
+                    .toList();
+            mKeyReadable = Set.copyOf(props.mKeyReadable);
+            mKeyWritable = Set.copyOf(props.mKeyWritable);
         }
 
-        try {
-            return (RavenwoodConfig) field.get(null);
-        } catch (IllegalAccessException e) {
-            throw new RavenwoodRuntimeException("Failed to fetch from the configuration field", e);
+        boolean isKeyAccessible(String key, boolean write) {
+            return write ? mKeyWritable.contains(key) : mKeyReadable.contains(key);
         }
-    }
 
-    /**
-     * @return true if the current target class (or its super classes) has any @Rule / @ClassRule
-     * fields of type RavenwoodRule.
-     *
-     * Note, this check won't detect cases where a Rule is of type
-     * {@link TestRule} and still be a {@link RavenwoodRule}. But that'll be detected at runtime
-     * as a failure, in {@link #enterRavenwoodRule}.
-     */
-    private static boolean hasRavenwoodRule(Class<?> testClass) {
-        for (var field : testClass.getDeclaredFields()) {
-            if (!field.isAnnotationPresent(Rule.class)
-                    && !field.isAnnotationPresent(ClassRule.class)) {
-                continue;
-            }
-            if (field.getType().equals(RavenwoodRule.class)) {
-                return true;
-            }
-        }
-        // JUnit supports rules as methods, so we need to check them too.
-        for (var method : testClass.getDeclaredMethods()) {
-            if (!method.isAnnotationPresent(Rule.class)
-                    && !method.isAnnotationPresent(ClassRule.class)) {
-                continue;
-            }
-            if (method.getReturnType().equals(RavenwoodRule.class)) {
-                return true;
-            }
-        }
-        // Look into the super class.
-        if (!testClass.getSuperclass().equals(Object.class)) {
-            return hasRavenwoodRule(testClass.getSuperclass());
-        }
-        return false;
-    }
-
-    /**
-     * Find and return a field with @RavenwoodConfig.Config, which must be of type
-     * RavenwoodConfig.
-     */
-    @Nullable
-    private static Field findConfigurationField(Class<?> testClass) {
-        Field foundField = null;
-
-        for (var field : testClass.getDeclaredFields()) {
-            final var hasAnot = field.isAnnotationPresent(RavenwoodConfig.Config.class);
-            final var isType = field.getType().equals(RavenwoodConfig.class);
-
-            if (hasAnot) {
-                if (isType) {
-                    // Good, use this field.
-                    if (foundField != null) {
-                        fail(String.format(
-                                "Class %s has multiple fields with %s",
-                                testClass.getCanonicalName(),
-                                "@RavenwoodConfig.Config"));
-                    }
-                    // Make sure it's static public
-                    ensureIsPublicMember(field, true);
-
-                    foundField = field;
+        void restore() {
+            mBackup.forEach(pair -> {
+                if (pair.second == null) {
+                    RavenwoodRuntimeNative.removeSystemProperty(pair.first);
                 } else {
-                    fail(String.format(
-                            "Field %s.%s has %s but type is not %s",
-                            testClass.getCanonicalName(),
-                            field.getName(),
-                            "@RavenwoodConfig.Config",
-                            "RavenwoodConfig"));
-                    return null; // unreachable
+                    RavenwoodRuntimeNative.setSystemProperty(pair.first, pair.second);
                 }
-            } else {
-                if (isType) {
-                    fail(String.format(
-                            "Field %s.%s does not have %s but type is %s",
-                            testClass.getCanonicalName(),
-                            field.getName(),
-                            "@RavenwoodConfig.Config",
-                            "RavenwoodConfig"));
-                    return null; // unreachable
-                } else {
-                    // Unrelated field, ignore.
-                    continue;
-                }
-            }
+            });
         }
-        if (foundField != null) {
-            return foundField;
+    }
+
+    private static void pushTestProperties(RavenwoodRule rule) {
+        sActiveProperties.add(Pair.create(rule, new RavenwoodPropertyState(rule.mProperties)));
+        rule.mProperties.mValues.forEach(RavenwoodRuntimeNative::setSystemProperty);
+    }
+
+    private static void popTestProperties(RavenwoodRule rule) {
+        var pair = sActiveProperties.removeLast();
+        assertNotNull(RAVENWOOD_RULE_ERROR, pair);
+        assertEquals(RAVENWOOD_RULE_ERROR, rule, pair.first);
+        pair.second.restore();
+    }
+
+    @SuppressWarnings("unused")  // Called from native code (ravenwood_sysprop.cpp)
+    private static void checkSystemPropertyAccess(String key, boolean write) {
+        if (write && RavenwoodSystemProperties.sDefaultValues.containsKey(key)) {
+            // The default core values should never be modified
+            throw new IllegalArgumentException(
+                    "Setting core system property '" + key + "' is not allowed");
         }
-        if (!testClass.getSuperclass().equals(Object.class)) {
-            return findConfigurationField(testClass.getSuperclass());
+
+        final boolean result = RavenwoodSystemProperties.isKeyAccessible(key, write)
+                || sActiveProperties.stream().anyMatch(p -> p.second.isKeyAccessible(key, write));
+
+        if (!result) {
+            throw new IllegalArgumentException((write ? "Write" : "Read")
+                    + " access to system property '" + key + "' denied via RavenwoodRule");
         }
-        return null;
     }
 }
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
index 979076e..172cec3 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
@@ -16,8 +16,11 @@
 
 package android.platform.test.ravenwood;
 
+import static android.os.Process.FIRST_APPLICATION_UID;
+import static android.os.UserHandle.SYSTEM;
 import static android.platform.test.ravenwood.RavenwoodSystemServer.ANDROID_PACKAGE_NAME;
 
+import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_EMPTY_RESOURCES_APK;
 import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_INST_RESOURCE_APK;
 import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_RESOURCE_APK;
 import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING;
@@ -25,7 +28,9 @@
 import static com.android.ravenwood.common.RavenwoodCommonUtils.parseNullableInt;
 import static com.android.ravenwood.common.RavenwoodCommonUtils.withDefault;
 
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
@@ -53,6 +58,8 @@
 import android.system.ErrnoException;
 import android.system.Os;
 import android.util.Log;
+import android.util.Log_ravenwood;
+import android.view.DisplayAdjustments;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
@@ -62,7 +69,6 @@
 import com.android.ravenwood.RavenwoodRuntimeNative;
 import com.android.ravenwood.RavenwoodRuntimeState;
 import com.android.ravenwood.common.RavenwoodCommonUtils;
-import com.android.ravenwood.common.RavenwoodRuntimeException;
 import com.android.ravenwood.common.SneakyThrow;
 import com.android.server.LocalServices;
 import com.android.server.compat.PlatformCompat;
@@ -74,8 +80,10 @@
 import java.io.IOException;
 import java.io.PrintStream;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
@@ -85,8 +93,7 @@
 import java.util.function.Supplier;
 
 /**
- * Responsible for initializing and de-initializing the environment, according to a
- * {@link RavenwoodConfig}.
+ * Responsible for initializing and the environment.
  */
 public class RavenwoodRuntimeEnvironmentController {
     private static final String TAG = "RavenwoodRuntimeEnvironmentController";
@@ -96,7 +103,6 @@
 
     private static final String MAIN_THREAD_NAME = "RavenwoodMain";
     private static final String LIBRAVENWOOD_INITIALIZER_NAME = "ravenwood_initializer";
-    private static final String RAVENWOOD_NATIVE_SYSPROP_NAME = "ravenwood_sysprop";
     private static final String RAVENWOOD_NATIVE_RUNTIME_NAME = "ravenwood_runtime";
 
     /**
@@ -113,8 +119,6 @@
 
     private static ScheduledFuture<?> sPendingTimeout;
 
-    private static long sOriginalIdentityToken = -1;
-
     /**
      * When enabled, attempt to detect uncaught exceptions from background threads.
      */
@@ -147,6 +151,10 @@
         return res;
     }
 
+    /** Map from path -> resources. */
+    private static final HashMap<File, Resources> sCachedResources = new HashMap<>();
+    private static Set<String> sAdoptedPermissions = Collections.emptySet();
+
     private static final Object sInitializationLock = new Object();
 
     @GuardedBy("sInitializationLock")
@@ -155,15 +163,16 @@
     @GuardedBy("sInitializationLock")
     private static Throwable sExceptionFromGlobalInit;
 
-    private static RavenwoodAwareTestRunner sRunner;
-    private static RavenwoodSystemProperties sProps;
-
     private static final int DEFAULT_TARGET_SDK_LEVEL = VERSION_CODES.CUR_DEVELOPMENT;
     private static final String DEFAULT_PACKAGE_NAME = "com.android.ravenwoodtests.defaultname";
 
+    private static final int sMyPid = new Random().nextInt(100, 32768);
     private static int sTargetSdkLevel;
     private static String sTestPackageName;
     private static String sTargetPackageName;
+    private static Instrumentation sInstrumentation;
+    private static final long sCallingIdentity =
+            packBinderIdentityToken(false, FIRST_APPLICATION_UID, sMyPid);
 
     /**
      * Initialize the global environment.
@@ -182,7 +191,7 @@
                     Log.e(TAG, "globalInit() failed", th);
 
                     sExceptionFromGlobalInit = th;
-                    throw th;
+                    SneakyThrow.sneakyThrow(th);
                 }
             } else {
                 // Subsequent calls. If the first call threw, just throw the same error, to prevent
@@ -197,30 +206,36 @@
         }
     }
 
-    private static void globalInitInner() {
+    private static void globalInitInner() throws IOException {
         if (RAVENWOOD_VERBOSE_LOGGING) {
             Log.v(TAG, "globalInit() called here...", new RuntimeException("NOT A CRASH"));
         }
+        if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) {
+            Thread.setDefaultUncaughtExceptionHandler(sUncaughtExceptionHandler);
+        }
 
-        // Some process-wide initialization. (maybe redirect stdout/stderr)
-        RavenwoodCommonUtils.loadJniLibrary(LIBRAVENWOOD_INITIALIZER_NAME);
+        // Some process-wide initialization:
+        // - maybe redirect stdout/stderr
+        // - override native system property functions
+        var lib = RavenwoodCommonUtils.getJniLibraryPath(LIBRAVENWOOD_INITIALIZER_NAME);
+        System.load(lib);
+        RavenwoodRuntimeNative.reloadNativeLibrary(lib);
+
+        // Redirect stdout/stdin to the Log API.
+        RuntimeInit.redirectLogStreams();
 
         dumpCommandLineArgs();
 
         // We haven't initialized liblog yet, so directly write to System.out here.
         RavenwoodCommonUtils.log(TAG, "globalInitInner()");
 
-        // Load libravenwood_sysprop before other libraries that may use SystemProperties.
-        var libProp = RavenwoodCommonUtils.getJniLibraryPath(RAVENWOOD_NATIVE_SYSPROP_NAME);
-        System.load(libProp);
-        RavenwoodRuntimeNative.reloadNativeLibrary(libProp);
-
         // Make sure libravenwood_runtime is loaded.
         System.load(RavenwoodCommonUtils.getJniLibraryPath(RAVENWOOD_NATIVE_RUNTIME_NAME));
 
+        Log_ravenwood.onRavenwoodRuntimeNativeReady();
+
         // Do the basic set up for the android sysprops.
         RavenwoodSystemProperties.initialize();
-        setSystemProperties(null);
 
         // Do this after loading RAVENWOOD_NATIVE_RUNTIME_NAME (which backs Os.setenv()),
         // before loadFrameworkNativeCode() (which uses $ANDROID_LOG_TAGS).
@@ -236,9 +251,6 @@
         // Make sure libandroid_runtime is loaded.
         RavenwoodNativeLoader.loadFrameworkNativeCode();
 
-        // Redirect stdout/stdin to liblog.
-        RuntimeInit.redirectLogStreams();
-
         // Touch some references early to ensure they're <clinit>'ed
         Objects.requireNonNull(Build.TYPE);
         Objects.requireNonNull(Build.VERSION.SDK);
@@ -251,6 +263,74 @@
         loadRavenwoodProperties();
 
         assertMockitoVersion();
+
+        Log.i(TAG, "TargetPackageName=" + sTargetPackageName);
+        Log.i(TAG, "TestPackageName=" + sTestPackageName);
+        Log.i(TAG, "TargetSdkLevel=" + sTargetSdkLevel);
+
+        RavenwoodRuntimeState.sUid = FIRST_APPLICATION_UID;
+        RavenwoodRuntimeState.sPid = sMyPid;
+        RavenwoodRuntimeState.sTargetSdkLevel = sTargetSdkLevel;
+
+        ServiceManager.init$ravenwood();
+        LocalServices.removeAllServicesForTest();
+
+        ActivityManager.init$ravenwood(SYSTEM.getIdentifier());
+
+        final var main = new HandlerThread(MAIN_THREAD_NAME);
+        main.start();
+        Looper.setMainLooperForTest(main.getLooper());
+
+        final boolean isSelfInstrumenting =
+                Objects.equals(sTestPackageName, sTargetPackageName);
+
+        // This will load the resources from the apk set to `resource_apk` in the build file.
+        // This is supposed to be the "target app"'s resources.
+        final Supplier<Resources> targetResourcesLoader = () -> {
+            var file = new File(RAVENWOOD_RESOURCE_APK);
+            return loadResources(file.exists() ? file : null);
+        };
+
+        // Set up test context's (== instrumentation context's) resources.
+        // If the target package name == test package name, then we use the main resources.
+        final Supplier<Resources> instResourcesLoader;
+        if (isSelfInstrumenting) {
+            instResourcesLoader = targetResourcesLoader;
+        } else {
+            instResourcesLoader = () -> {
+                var file = new File(RAVENWOOD_INST_RESOURCE_APK);
+                return loadResources(file.exists() ? file : null);
+            };
+        }
+
+        var instContext = new RavenwoodContext(
+                sTestPackageName, main, instResourcesLoader);
+        var targetContext = new RavenwoodContext(
+                sTargetPackageName, main, targetResourcesLoader);
+
+        // Set up app context.
+        var appContext = new RavenwoodContext(sTargetPackageName, main, targetResourcesLoader);
+        appContext.setApplicationContext(appContext);
+        if (isSelfInstrumenting) {
+            instContext.setApplicationContext(appContext);
+            targetContext.setApplicationContext(appContext);
+        } else {
+            // When instrumenting into another APK, the test context doesn't have an app context.
+            targetContext.setApplicationContext(appContext);
+        }
+
+        final Supplier<Resources> systemResourcesLoader = () -> loadResources(null);
+
+        var systemServerContext =
+                new RavenwoodContext(ANDROID_PACKAGE_NAME, main, systemResourcesLoader);
+
+        sInstrumentation = new Instrumentation();
+        sInstrumentation.basicInit(instContext, targetContext, null);
+        InstrumentationRegistry.registerInstance(sInstrumentation, Bundle.EMPTY);
+
+        RavenwoodSystemServer.init(systemServerContext);
+
+        initializeCompatIds();
     }
 
     private static void loadRavenwoodProperties() {
@@ -265,134 +345,41 @@
     }
 
     /**
-     * Initialize the environment.
+     * Partially reset and initialize before each test class invocation
      */
-    public static void init(RavenwoodAwareTestRunner runner) {
-        if (RAVENWOOD_VERBOSE_LOGGING) {
-            Log.v(TAG, "init() called here: " + runner, new RuntimeException("STACKTRACE"));
-        }
-        if (sRunner == runner) {
-            return;
-        }
-        if (sRunner != null) {
-            reset();
-        }
-        sRunner = runner;
-        try {
-            initInner(runner.mState.getConfig());
-        } catch (Exception th) {
-            Log.e(TAG, "init() failed", th);
+    public static void initForRunner() {
+        var targetContext = sInstrumentation.getTargetContext();
+        var instContext = sInstrumentation.getContext();
+        // We need to recreate the mock UiAutomation for each test class, because sometimes tests
+        // will call Mockito.framework().clearInlineMocks() after execution.
+        sInstrumentation.basicInit(instContext, targetContext, createMockUiAutomation());
 
-            RavenwoodCommonUtils.runIgnoringException(()-> reset());
+        // Reset some global state
+        Process_ravenwood.reset();
+        DeviceConfig_host.reset();
+        Binder.restoreCallingIdentity(sCallingIdentity);
 
-            SneakyThrow.sneakyThrow(th);
-        }
-    }
-
-    private static void initInner(RavenwoodConfig config) throws IOException {
-        if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) {
-            maybeThrowPendingUncaughtException(false);
-            Thread.setDefaultUncaughtExceptionHandler(sUncaughtExceptionHandler);
-        }
-
-        config.mTargetPackageName = sTargetPackageName;
-        config.mTestPackageName = sTestPackageName;
-        config.mTargetSdkLevel = sTargetSdkLevel;
-
-        Log.i(TAG, "TargetPackageName=" + sTargetPackageName);
-        Log.i(TAG, "TestPackageName=" + sTestPackageName);
-        Log.i(TAG, "TargetSdkLevel=" + sTargetSdkLevel);
-
-        RavenwoodRuntimeState.sUid = config.mUid;
-        RavenwoodRuntimeState.sPid = config.mPid;
-        RavenwoodRuntimeState.sTargetSdkLevel = config.mTargetSdkLevel;
-        sOriginalIdentityToken = Binder.clearCallingIdentity();
-        reinit();
-        setSystemProperties(config.mSystemProperties);
-
-        ServiceManager.init$ravenwood();
-        LocalServices.removeAllServicesForTest();
-
-        ActivityManager.init$ravenwood(config.mCurrentUser);
-
-        final var main = new HandlerThread(MAIN_THREAD_NAME);
-        main.start();
-        Looper.setMainLooperForTest(main.getLooper());
-
-        final boolean isSelfInstrumenting =
-                Objects.equals(config.mTestPackageName, config.mTargetPackageName);
-
-        // This will load the resources from the apk set to `resource_apk` in the build file.
-        // This is supposed to be the "target app"'s resources.
-        final Supplier<Resources> targetResourcesLoader = () -> {
-            var file = new File(RAVENWOOD_RESOURCE_APK);
-            return config.mState.loadResources(file.exists() ? file : null);
-        };
-
-        // Set up test context's (== instrumentation context's) resources.
-        // If the target package name == test package name, then we use the main resources.
-        final Supplier<Resources> instResourcesLoader;
-        if (isSelfInstrumenting) {
-            instResourcesLoader = targetResourcesLoader;
-        } else {
-            instResourcesLoader = () -> {
-                var file = new File(RAVENWOOD_INST_RESOURCE_APK);
-                return config.mState.loadResources(file.exists() ? file : null);
-            };
-        }
-
-        var instContext = new RavenwoodContext(
-                config.mTestPackageName, main, instResourcesLoader);
-        var targetContext = new RavenwoodContext(
-                config.mTargetPackageName, main, targetResourcesLoader);
-
-        // Set up app context.
-        var appContext = new RavenwoodContext(
-                config.mTargetPackageName, main, targetResourcesLoader);
-        appContext.setApplicationContext(appContext);
-        if (isSelfInstrumenting) {
-            instContext.setApplicationContext(appContext);
-            targetContext.setApplicationContext(appContext);
-        } else {
-            // When instrumenting into another APK, the test context doesn't have an app context.
-            targetContext.setApplicationContext(appContext);
-        }
-        config.mInstContext = instContext;
-        config.mTargetContext = targetContext;
-
-        final Supplier<Resources> systemResourcesLoader = () -> config.mState.loadResources(null);
-
-        config.mState.mSystemServerContext =
-                new RavenwoodContext(ANDROID_PACKAGE_NAME, main, systemResourcesLoader);
-
-        // Prepare other fields.
-        config.mInstrumentation = new Instrumentation();
-        config.mInstrumentation.basicInit(instContext, targetContext, createMockUiAutomation());
-        InstrumentationRegistry.registerInstance(config.mInstrumentation, Bundle.EMPTY);
-
-        RavenwoodSystemServer.init(config);
-
-        initializeCompatIds(config);
+        SystemProperties.clearChangeCallbacksForTest();
 
         if (ENABLE_TIMEOUT_STACKS) {
             sPendingTimeout = sTimeoutExecutor.schedule(
                     RavenwoodRuntimeEnvironmentController::dumpStacks,
                     TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
         }
-    }
-
-    /**
-     * Partially re-initialize after each test method invocation
-     */
-    public static void reinit() {
-        // sRunner could be null, if there was a failure in the initialization.
-        if (sRunner != null) {
-            var config = sRunner.mState.getConfig();
-            Binder.restoreCallingIdentity(packBinderIdentityToken(false, config.mUid, config.mPid));
+        if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) {
+            maybeThrowPendingUncaughtException(false);
         }
     }
 
-    private static void initializeCompatIds(RavenwoodConfig config) {
+    /**
+     * Partially reset and initialize before each test method invocation
+     */
+    public static void initForMethod() {
+        // TODO(b/375272444): this is a hacky workaround to ensure binder identity
+        Binder.restoreCallingIdentity(sCallingIdentity);
+    }
+
+    private static void initializeCompatIds() {
         // Set up compat-IDs for the app side.
         // TODO: Inside the system server, all the compat-IDs should be enabled,
         // Due to the `AppCompatCallbacks.install(new long[0], new long[0])` call in
@@ -400,8 +387,8 @@
 
         // Compat framework only uses the package name and the target SDK level.
         ApplicationInfo appInfo = new ApplicationInfo();
-        appInfo.packageName = config.mTargetPackageName;
-        appInfo.targetSdkVersion = config.mTargetSdkLevel;
+        appInfo.packageName = sTargetPackageName;
+        appInfo.targetSdkVersion = sTargetSdkLevel;
 
         PlatformCompat platformCompat = null;
         try {
@@ -418,65 +405,42 @@
     }
 
     /**
-     * De-initialize.
-     *
-     * Note, we call this method when init() fails too, so this method should deal with
-     * any partially-initialized states.
+     * Load {@link Resources} from an APK, with cache.
      */
-    public static void reset() {
-        if (RAVENWOOD_VERBOSE_LOGGING) {
-            Log.v(TAG, "reset() called here", new RuntimeException("STACKTRACE"));
+    private static Resources loadResources(@Nullable File apkPath) {
+        var cached = sCachedResources.get(apkPath);
+        if (cached != null) {
+            return cached;
         }
-        if (sRunner == null) {
-            throw new RavenwoodRuntimeException("Internal error: reset() already called");
-        }
-        var config = sRunner.mState.getConfig();
-        sRunner = null;
 
+        var fileToLoad = apkPath != null ? apkPath : new File(RAVENWOOD_EMPTY_RESOURCES_APK);
+
+        assertTrue("File " + fileToLoad + " doesn't exist.", fileToLoad.isFile());
+
+        final String path = fileToLoad.getAbsolutePath();
+        final var emptyPaths = new String[0];
+
+        ResourcesManager.getInstance().initializeApplicationPaths(path, emptyPaths);
+
+        final var ret = ResourcesManager.getInstance().getResources(null, path,
+                emptyPaths, emptyPaths, emptyPaths,
+                emptyPaths, null, null,
+                new DisplayAdjustments().getCompatibilityInfo(),
+                RavenwoodRuntimeEnvironmentController.class.getClassLoader(), null);
+
+        assertNotNull(ret);
+
+        sCachedResources.put(apkPath, ret);
+        return ret;
+    }
+
+    /**
+     * A callback when a test class finishes its execution, mostly only for debugging.
+     */
+    public static void exitTestClass() {
         if (ENABLE_TIMEOUT_STACKS) {
             sPendingTimeout.cancel(false);
         }
-
-        RavenwoodSystemServer.reset(config);
-
-        InstrumentationRegistry.registerInstance(null, Bundle.EMPTY);
-        config.mInstrumentation = null;
-        if (config.mInstContext != null) {
-            ((RavenwoodContext) config.mInstContext).cleanUp();
-            config.mInstContext = null;
-        }
-        if (config.mTargetContext != null) {
-            ((RavenwoodContext) config.mTargetContext).cleanUp();
-            config.mTargetContext = null;
-        }
-        if (config.mState.mSystemServerContext != null) {
-            config.mState.mSystemServerContext.cleanUp();
-        }
-
-        if (Looper.getMainLooper() != null) {
-            Looper.getMainLooper().quit();
-        }
-        Looper.clearMainLooperForTest();
-
-        ActivityManager.reset$ravenwood();
-
-        LocalServices.removeAllServicesForTest();
-        ServiceManager.reset$ravenwood();
-
-        setSystemProperties(null);
-        if (sOriginalIdentityToken != -1) {
-            Binder.restoreCallingIdentity(sOriginalIdentityToken);
-        }
-        RavenwoodRuntimeState.reset();
-        Process_ravenwood.reset();
-        DeviceConfig_host.reset();
-
-        try {
-            ResourcesManager.setInstance(null); // Better structure needed.
-        } catch (Exception e) {
-            // AOSP-CHANGE: AOSP doesn't support resources yet.
-        }
-
         if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) {
             maybeThrowPendingUncaughtException(true);
         }
@@ -521,19 +485,6 @@
         }
     }
 
-    /**
-     * Set the current configuration to the actual SystemProperties.
-     */
-    private static void setSystemProperties(@Nullable RavenwoodSystemProperties systemProperties) {
-        SystemProperties.clearChangeCallbacksForTest();
-        RavenwoodRuntimeNative.clearSystemProperties();
-        if (systemProperties == null) systemProperties = new RavenwoodSystemProperties();
-        sProps = new RavenwoodSystemProperties(systemProperties, true);
-        for (var entry : systemProperties.getValues().entrySet()) {
-            RavenwoodRuntimeNative.setSystemProperty(entry.getKey(), entry.getValue());
-        }
-    }
-
     private static final String MOCKITO_ERROR = "FATAL: Unsupported Mockito detected!"
             + " Your test or its dependencies use one of the \"mockito-target-*\""
             + " modules as static library, which is unusable on host side."
@@ -558,40 +509,31 @@
 
     // TODO: use the real UiAutomation class instead of a mock
     private static UiAutomation createMockUiAutomation() {
-        final Set[] adoptedPermission = { Collections.emptySet() };
+        sAdoptedPermissions = Collections.emptySet();
         var mock = mock(UiAutomation.class, inv -> {
             HostTestUtils.onThrowMethodCalled();
             return null;
         });
         doAnswer(inv -> {
-            adoptedPermission[0] = UiAutomation.ALL_PERMISSIONS;
+            sAdoptedPermissions = UiAutomation.ALL_PERMISSIONS;
             return null;
         }).when(mock).adoptShellPermissionIdentity();
         doAnswer(inv -> {
             if (inv.getArgument(0) == null) {
-                adoptedPermission[0] = UiAutomation.ALL_PERMISSIONS;
+                sAdoptedPermissions = UiAutomation.ALL_PERMISSIONS;
             } else {
-                adoptedPermission[0] = Set.of(inv.getArguments());
+                sAdoptedPermissions = (Set) Set.of(inv.getArguments());
             }
             return null;
         }).when(mock).adoptShellPermissionIdentity(any());
         doAnswer(inv -> {
-            adoptedPermission[0] = Collections.emptySet();
+            sAdoptedPermissions = Collections.emptySet();
             return null;
         }).when(mock).dropShellPermissionIdentity();
-        doAnswer(inv -> adoptedPermission[0]).when(mock).getAdoptedShellPermissions();
+        doAnswer(inv -> sAdoptedPermissions).when(mock).getAdoptedShellPermissions();
         return mock;
     }
 
-    @SuppressWarnings("unused")  // Called from native code (ravenwood_sysprop.cpp)
-    private static void checkSystemPropertyAccess(String key, boolean write) {
-        boolean result = write ? sProps.isKeyWritable(key) : sProps.isKeyReadable(key);
-        if (!result) {
-            throw new IllegalArgumentException((write ? "Write" : "Read")
-                    + " access to system property '" + key + "' denied via RavenwoodConfig");
-        }
-    }
-
     private static void dumpCommandLineArgs() {
         Log.i(TAG, "JVM arguments:");
 
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
similarity index 67%
rename from ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
rename to ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
index 9bd376a..99b38ed 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package android.platform.test.ravenwood;
 
 import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING;
@@ -21,26 +20,30 @@
 
 import android.util.Log;
 
+import com.android.ravenwood.RavenwoodRuntimeNative;
+
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
+/**
+ * A class to manage the core default system properties of the Ravenwood environment.
+ */
 public class RavenwoodSystemProperties {
     private static final String TAG = "RavenwoodSystemProperties";
 
-    /** We pull in propeties from this file. */
+    /** We pull in properties from this file. */
     private static final String RAVENWOOD_BUILD_PROP = "ravenwood-data/ravenwood-build.prop";
 
     /** This is the actual build.prop we use to build the device (contents depends on lunch). */
     private static final String DEVICE_BUILD_PROP = "ravenwood-data/build.prop";
 
     /** The default values. */
-    private static final Map<String, String> sDefaultValues = new HashMap<>();
+    static final Map<String, String> sDefaultValues = new HashMap<>();
 
     private static final String[] PARTITIONS = {
             "bootimage",
@@ -91,7 +94,7 @@
                 var deviceValue = deviceProps.get(deviceKey);
                 if (deviceValue == null) {
                     throw new RuntimeException("Failed to initialize system properties. Key '"
-                             + deviceKey + "' doesn't exist in the device side build.prop");
+                            + deviceKey + "' doesn't exist in the device side build.prop");
                 }
                 value = deviceValue;
             } else {
@@ -115,6 +118,7 @@
                 }
             }
         }
+
         if (RAVENWOOD_VERBOSE_LOGGING) {
             // Dump all properties for local debugging.
             Log.v(TAG, "All system properties:");
@@ -122,39 +126,17 @@
                 Log.v(TAG, "" + key + "=" + sDefaultValues.get(key));
             }
         }
+
+        // Actually set the system properties
+        sDefaultValues.forEach(RavenwoodRuntimeNative::setSystemProperty);
     }
 
-    private volatile boolean mIsImmutable;
+    private static boolean isKeyReadable(String key) {
+        // All writable keys are also readable
+        if (isKeyWritable(key)) return true;
 
-    private final Map<String, String> mValues = new HashMap<>();
-
-    /** Set of additional keys that should be considered readable */
-    private final Set<String> mKeyReadable = new HashSet<>();
-
-    /** Set of additional keys that should be considered writable */
-    private final Set<String> mKeyWritable = new HashSet<>();
-
-    public RavenwoodSystemProperties() {
-        mValues.putAll(sDefaultValues);
-    }
-
-    /** Copy constructor */
-    public RavenwoodSystemProperties(RavenwoodSystemProperties source, boolean immutable) {
-        mKeyReadable.addAll(source.mKeyReadable);
-        mKeyWritable.addAll(source.mKeyWritable);
-        mValues.putAll(source.mValues);
-        mIsImmutable = immutable;
-    }
-
-    public Map<String, String> getValues() {
-        return new HashMap<>(mValues);
-    }
-
-    public boolean isKeyReadable(String key) {
         final String root = getKeyRoot(key);
 
-        if (root.startsWith("debug.")) return true;
-
         // This set is carefully curated to help identify situations where a test may
         // accidentally depend on a default value of an obscure property whose owner hasn't
         // decided how Ravenwood should behave.
@@ -164,29 +146,27 @@
         if (root.startsWith("soc.")) return true;
         if (root.startsWith("system.")) return true;
 
-        // For PropertyInvalidatedCache
-        if (root.startsWith("cache_key.")) return true;
+        // All core values should be readable
+        if (sDefaultValues.containsKey(key)) return true;
 
-        switch (key) {
-            case "gsm.version.baseband":
-            case "no.such.thing":
-            case "qemu.sf.lcd_density":
-            case "ro.bootloader":
-            case "ro.debuggable":
-            case "ro.hardware":
-            case "ro.hw_timeout_multiplier":
-            case "ro.odm.build.media_performance_class":
-            case "ro.sf.lcd_density":
-            case "ro.treble.enabled":
-            case "ro.vndk.version":
-            case "ro.icu.data.path":
-                return true;
-        }
-
-        return mKeyReadable.contains(key);
+        // Hardcoded allowlist
+        return switch (key) {
+            case "gsm.version.baseband",
+                 "no.such.thing",
+                 "qemu.sf.lcd_density",
+                 "ro.bootloader",
+                 "ro.hardware",
+                 "ro.hw_timeout_multiplier",
+                 "ro.odm.build.media_performance_class",
+                 "ro.sf.lcd_density",
+                 "ro.treble.enabled",
+                 "ro.vndk.version",
+                 "ro.icu.data.path" -> true;
+            default -> false;
+        };
     }
 
-    public boolean isKeyWritable(String key) {
+    private static boolean isKeyWritable(String key) {
         final String root = getKeyRoot(key);
 
         if (root.startsWith("debug.")) return true;
@@ -194,42 +174,11 @@
         // For PropertyInvalidatedCache
         if (root.startsWith("cache_key.")) return true;
 
-        return mKeyWritable.contains(key);
+        return false;
     }
 
-    private void ensureNotImmutable() {
-        if (mIsImmutable) {
-            throw new RuntimeException("Unable to update immutable instance");
-        }
-    }
-
-    public void setValue(String key, Object value) {
-        ensureNotImmutable();
-
-        final String valueString = (value == null) ? null : String.valueOf(value);
-        if ((valueString == null) || valueString.isEmpty()) {
-            mValues.remove(key);
-        } else {
-            mValues.put(key, valueString);
-        }
-    }
-
-    public void setAccessNone(String key) {
-        ensureNotImmutable();
-        mKeyReadable.remove(key);
-        mKeyWritable.remove(key);
-    }
-
-    public void setAccessReadOnly(String key) {
-        ensureNotImmutable();
-        mKeyReadable.add(key);
-        mKeyWritable.remove(key);
-    }
-
-    public void setAccessReadWrite(String key) {
-        ensureNotImmutable();
-        mKeyReadable.add(key);
-        mKeyWritable.add(key);
+    static boolean isKeyAccessible(String key, boolean write) {
+        return write ? isKeyWritable(key) : isKeyReadable(key);
     }
 
     /**
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
index 438a2bf..3346635 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
@@ -33,7 +33,7 @@
 import com.android.server.compat.PlatformCompatNative;
 import com.android.server.utils.TimingsTraceAndSlog;
 
-import java.util.List;
+import java.util.Collection;
 import java.util.Set;
 
 public class RavenwoodSystemServer {
@@ -68,27 +68,24 @@
     private static TimingsTraceAndSlog sTimings;
     private static SystemServiceManager sServiceManager;
 
-    public static void init(RavenwoodConfig config) {
+    public static void init(Context systemServerContext) {
         // Always start PlatformCompat, regardless of the requested services.
         // PlatformCompat is not really a SystemService, so it won't receive boot phases / etc.
         // This initialization code is copied from SystemServer.java.
-        PlatformCompat platformCompat = new PlatformCompat(config.mState.mSystemServerContext);
+        PlatformCompat platformCompat = new PlatformCompat(systemServerContext);
         ServiceManager.addService(Context.PLATFORM_COMPAT_SERVICE, platformCompat);
         ServiceManager.addService(Context.PLATFORM_COMPAT_NATIVE_SERVICE,
                 new PlatformCompatNative(platformCompat));
 
-        // Avoid overhead if no services required
-        if (config.mServicesRequired.isEmpty()) return;
-
         sStartedServices = new ArraySet<>();
         sTimings = new TimingsTraceAndSlog();
-        sServiceManager = new SystemServiceManager(config.mState.mSystemServerContext);
+        sServiceManager = new SystemServiceManager(systemServerContext);
         sServiceManager.setStartInfo(false,
                 SystemClock.elapsedRealtime(),
                 SystemClock.uptimeMillis());
         LocalServices.addService(SystemServiceManager.class, sServiceManager);
 
-        startServices(config.mServicesRequired);
+        startServices(sKnownServices.keySet());
         sServiceManager.sealStartedServices();
 
         // TODO: expand to include additional boot phases when relevant
@@ -96,7 +93,7 @@
         sServiceManager.startBootPhase(sTimings, SystemService.PHASE_BOOT_COMPLETED);
     }
 
-    public static void reset(RavenwoodConfig config) {
+    public static void reset() {
         // TODO: consider introducing shutdown boot phases
 
         LocalServices.removeServiceForTest(SystemServiceManager.class);
@@ -105,7 +102,7 @@
         sStartedServices = null;
     }
 
-    private static void startServices(List<Class<?>> serviceClasses) {
+    private static void startServices(Collection<Class<?>> serviceClasses) {
         for (Class<?> serviceClass : serviceClasses) {
             // Quietly ignore duplicate requests if service already started
             if (sStartedServices.contains(serviceClass)) continue;
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
index 7ca9239..3ed0f50 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
@@ -15,21 +15,13 @@
  */
 package android.platform.test.ravenwood;
 
-import static android.os.Process.FIRST_APPLICATION_UID;
-import static android.os.UserHandle.SYSTEM;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.Instrumentation;
-import android.content.Context;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * @deprecated This class will be removed. Reach out to g/ravenwood if you need any features in it.
@@ -45,37 +37,10 @@
     public @interface Config {
     }
 
-    private static final int NOBODY_UID = 9999;
-
-    private static final AtomicInteger sNextPid = new AtomicInteger(100);
-
-    int mCurrentUser = SYSTEM.getIdentifier();
-
-    /**
-     * Unless the test author requests differently, run as "nobody", and give each collection of
-     * tests its own unique PID.
-     */
-    int mUid = FIRST_APPLICATION_UID;
-    int mPid = sNextPid.getAndIncrement();
-
-    String mTestPackageName;
-    String mTargetPackageName;
-
-    int mTargetSdkLevel;
-
-    final RavenwoodSystemProperties mSystemProperties = new RavenwoodSystemProperties();
-
-    final List<Class<?>> mServicesRequired = new ArrayList<>();
-
-    volatile Context mInstContext;
-    volatile Context mTargetContext;
-    volatile Instrumentation mInstrumentation;
-
     /**
      * Stores internal states / methods associated with this config that's only needed in
      * junit-impl.
      */
-    final RavenwoodConfigState mState = new RavenwoodConfigState(this);
     private RavenwoodConfig() {
     }
 
@@ -159,34 +124,11 @@
             return this;
         }
 
-        Builder setSystemPropertyImmutableReal(@NonNull String key,
-                @Nullable Object value) {
-            mConfig.mSystemProperties.setValue(key, value);
-            mConfig.mSystemProperties.setAccessReadOnly(key);
-            return this;
-        }
-
-        Builder setSystemPropertyMutableReal(@NonNull String key,
-                @Nullable Object value) {
-            mConfig.mSystemProperties.setValue(key, value);
-            mConfig.mSystemProperties.setAccessReadWrite(key);
-            return this;
-        }
-
         /**
-         * Configure the set of system services that are required for this test to operate.
-         *
-         * For example, passing {@code android.hardware.SerialManager.class} as an argument will
-         * ensure that the underlying service is created, initialized, and ready to use for the
-         * duration of the test. The {@code SerialManager} instance can be obtained via
-         * {@code RavenwoodRule.getContext()} and {@code Context.getSystemService()}, and
-         * {@code SerialManagerInternal} can be obtained via {@code LocalServices.getService()}.
+         * @deprecated no longer used. All supported services are available.
          */
+        @Deprecated
         public Builder setServicesRequired(@NonNull Class<?>... services) {
-            mConfig.mServicesRequired.clear();
-            for (Class<?> service : services) {
-                mConfig.mServicesRequired.add(service);
-            }
             return this;
         }
 
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index 5681a90..e49d3d9 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -92,19 +92,11 @@
         }
     }
 
-    private final RavenwoodConfig mConfiguration;
-
-    public RavenwoodRule() {
-        mConfiguration = new RavenwoodConfig.Builder().build();
-    }
-
-    private RavenwoodRule(RavenwoodConfig config) {
-        mConfiguration = config;
-    }
+    final RavenwoodTestProperties mProperties = new RavenwoodTestProperties();
 
     public static class Builder {
-        private final RavenwoodConfig.Builder mBuilder =
-                new RavenwoodConfig.Builder();
+
+        private final RavenwoodRule mRule = new RavenwoodRule();
 
         public Builder() {
         }
@@ -152,7 +144,8 @@
          * Has no effect on non-Ravenwood environments.
          */
         public Builder setSystemPropertyImmutable(@NonNull String key, @Nullable Object value) {
-            mBuilder.setSystemPropertyImmutableReal(key, value);
+            mRule.mProperties.setValue(key, value);
+            mRule.mProperties.setAccessReadOnly(key);
             return this;
         }
 
@@ -167,26 +160,21 @@
          * Has no effect on non-Ravenwood environments.
          */
         public Builder setSystemPropertyMutable(@NonNull String key, @Nullable Object value) {
-            mBuilder.setSystemPropertyMutableReal(key, value);
+            mRule.mProperties.setValue(key, value);
+            mRule.mProperties.setAccessReadWrite(key);
             return this;
         }
 
         /**
-         * Configure the set of system services that are required for this test to operate.
-         *
-         * For example, passing {@code android.hardware.SerialManager.class} as an argument will
-         * ensure that the underlying service is created, initialized, and ready to use for the
-         * duration of the test. The {@code SerialManager} instance can be obtained via
-         * {@code RavenwoodRule.getContext()} and {@code Context.getSystemService()}, and
-         * {@code SerialManagerInternal} can be obtained via {@code LocalServices.getService()}.
+         * @deprecated no longer used. All supported services are available.
          */
+        @Deprecated
         public Builder setServicesRequired(@NonNull Class<?>... services) {
-            mBuilder.setServicesRequired(services);
             return this;
         }
 
         public RavenwoodRule build() {
-            return new RavenwoodRule(mBuilder.build());
+            return mRule;
         }
     }
 
@@ -227,7 +215,7 @@
 
     @Override
     public Statement apply(Statement base, Description description) {
-        if (!RavenwoodConfig.isOnRavenwood()) {
+        if (!IS_ON_RAVENWOOD) {
             return base;
         }
         return new Statement() {
@@ -296,8 +284,4 @@
     public static RavenwoodPrivate private$ravenwood() {
         return sRavenwoodPrivate;
     }
-
-    RavenwoodConfig getConfiguration() {
-        return mConfiguration;
-    }
 }
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodTestProperties.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodTestProperties.java
new file mode 100644
index 0000000..66a26b5
--- /dev/null
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodTestProperties.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 android.platform.test.ravenwood;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A class to store system properties defined by tests.
+ */
+public class RavenwoodTestProperties {
+    final Map<String, String> mValues = new HashMap<>();
+
+    /** Set of additional keys that should be considered readable */
+    final Set<String> mKeyReadable = new HashSet<>();
+
+    /** Set of additional keys that should be considered writable */
+    final Set<String> mKeyWritable = new HashSet<>();
+
+    public void setValue(String key, Object value) {
+        final String valueString = (value == null) ? null : String.valueOf(value);
+        if ((valueString == null) || valueString.isEmpty()) {
+            mValues.remove(key);
+        } else {
+            mValues.put(key, valueString);
+        }
+    }
+
+    public void setAccessNone(String key) {
+        mKeyReadable.remove(key);
+        mKeyWritable.remove(key);
+    }
+
+    public void setAccessReadOnly(String key) {
+        mKeyReadable.add(key);
+        mKeyWritable.remove(key);
+    }
+
+    public void setAccessReadWrite(String key) {
+        mKeyReadable.add(key);
+        mKeyWritable.add(key);
+    }
+}
diff --git a/ravenwood/runtime-helper-src/framework/android/util/Log_host.java b/ravenwood/runtime-helper-src/framework/android/util/Log_ravenwood.java
similarity index 62%
rename from ravenwood/runtime-helper-src/framework/android/util/Log_host.java
rename to ravenwood/runtime-helper-src/framework/android/util/Log_ravenwood.java
index c85bd23..7b26fe5 100644
--- a/ravenwood/runtime-helper-src/framework/android/util/Log_host.java
+++ b/ravenwood/runtime-helper-src/framework/android/util/Log_ravenwood.java
@@ -18,9 +18,13 @@
 import android.util.Log.Level;
 
 import com.android.internal.os.RuntimeInit;
+import com.android.ravenwood.RavenwoodRuntimeNative;
 import com.android.ravenwood.common.RavenwoodCommonUtils;
 
 import java.io.PrintStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
 
 /**
  * Ravenwood "native substitution" class for {@link android.util.Log}.
@@ -29,7 +33,10 @@
  * In order to switch to this Java implementation, uncomment the @RavenwoodNativeSubstitutionClass
  * annotation on {@link android.util.Log}.
  */
-public class Log_host {
+public class Log_ravenwood {
+
+    public static final SimpleDateFormat sTimestampFormat =
+            new SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US);
 
     public static boolean isLoggable(String tag, @Level int level) {
         return true;
@@ -39,15 +46,6 @@
         if (priority < Log.INFO && !RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING) {
             return msg.length(); // No verbose logging.
         }
-        final String buffer;
-        switch (bufID) {
-            case Log.LOG_ID_MAIN: buffer = "main"; break;
-            case Log.LOG_ID_RADIO: buffer = "radio"; break;
-            case Log.LOG_ID_EVENTS: buffer = "event"; break;
-            case Log.LOG_ID_SYSTEM: buffer = "system"; break;
-            case Log.LOG_ID_CRASH: buffer = "crash"; break;
-            default: buffer = "buf:" + bufID; break;
-        }
 
         final String prio;
         switch (priority) {
@@ -60,8 +58,12 @@
             default: prio = "prio:" + priority; break;
         }
 
+        String leading =  sTimestampFormat.format(new Date())
+                + " %-6d %-6d %s %-8s: ".formatted(getPid(), getTid(), prio, tag);
+        var out = getRealOut();
         for (String s : msg.split("\\n")) {
-            getRealOut().println(String.format("logd: [%s] %s %s: %s", buffer, prio, tag, s));
+            out.print(leading);
+            out.println(s);
         }
         return msg.length();
     }
@@ -81,4 +83,34 @@
             return System.out;
         }
     }
+
+    /**
+     * PID. We need to use a JNI method to get it, but JNI isn't initially ready.
+     * Call {@link #onRavenwoodRuntimeNativeReady} to signal when JNI is ready, at which point
+     * we set this field.
+     * (We don't want to call native methods that may not be fully initialized even with a
+     * try-catch, because partially initialized JNI methods could crash the process.)
+     */
+    private static volatile int sPid = 0;
+
+    private static ThreadLocal<Integer> sTid =
+            ThreadLocal.withInitial(RavenwoodRuntimeNative::gettid);
+
+    /**
+     * Call it when {@link RavenwoodRuntimeNative} is usable.
+     */
+    public static void onRavenwoodRuntimeNativeReady() {
+        sPid = RavenwoodRuntimeNative.getpid();
+    }
+
+    private static int getPid() {
+        return sPid;
+    }
+
+    private static int getTid() {
+        if (sPid == 0) {
+            return 0; // Native methods not ready yet.
+        }
+        return sTid.get();
+    }
 }
diff --git a/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java
index 7b940b4..acbcdf1 100644
--- a/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java
+++ b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java
@@ -56,7 +56,13 @@
 
     public static native boolean setSystemProperty(String key, String value);
 
-    public static native void clearSystemProperties();
+    public static native boolean removeSystemProperty(String key);
+
+    public static void clearSystemProperties() {
+        removeSystemProperty(null);
+    }
+
+    public static native int getpid();
 
     public static native int gettid();
 
diff --git a/ravenwood/runtime-jni/jni_helper.h b/ravenwood/runtime-jni/jni_helper.h
index 561fb3b..25d7519 100644
--- a/ravenwood/runtime-jni/jni_helper.h
+++ b/ravenwood/runtime-jni/jni_helper.h
@@ -26,6 +26,7 @@
 constexpr const char* kCommonUtils = "com/android/ravenwood/common/RavenwoodCommonUtils";
 constexpr const char* kRuntimeEnvController =
         "android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController";
+constexpr const char* kRunnerState = "android/platform/test/ravenwood/RavenwoodRunnerState";
 constexpr const char* kRuntimeNative = "com/android/ravenwood/RavenwoodRuntimeNative";
 
 // We have to explicitly decode the string to real UTF-8, because when using GetStringUTFChars
diff --git a/ravenwood/runtime-jni/ravenwood_initializer.cpp b/ravenwood/runtime-jni/ravenwood_initializer.cpp
index 89fb7c3..dbbc345 100644
--- a/ravenwood/runtime-jni/ravenwood_initializer.cpp
+++ b/ravenwood/runtime-jni/ravenwood_initializer.cpp
@@ -14,16 +14,174 @@
  * limitations under the License.
  */
 
- /*
-  * This file is compiled into a single SO file, which we load at the very first.
-  * We can do process-wide initialization here.
-  */
+/*
+ * This file is compiled into a single SO file, which we load at the very first.
+ * We can do process-wide initialization here.
+ * Please be aware that all symbols defined in this SO file will be reloaded
+ * as `RTLD_GLOBAL`, so make sure all functions are static except those we EXPLICITLY
+ * want to expose and override globally.
+ */
 
+#include <dlfcn.h>
 #include <fcntl.h>
-#include <unistd.h>
+
+#include <set>
 
 #include "jni_helper.h"
 
+// Implement a rudimentary system properties data store
+
+#define PROP_VALUE_MAX 92
+
+namespace {
+
+struct prop_info {
+    std::string key;
+    mutable std::string value;
+    mutable uint32_t serial;
+
+    prop_info(const char* key, const char* value) : key(key), value(value), serial(0) {}
+};
+
+struct prop_info_cmp {
+    using is_transparent = void;
+    bool operator()(const prop_info& lhs, const prop_info& rhs) {
+        return lhs.key < rhs.key;
+    }
+    bool operator()(std::string_view lhs, const prop_info& rhs) {
+        return lhs < rhs.key;
+    }
+    bool operator()(const prop_info& lhs, std::string_view rhs) {
+        return lhs.key < rhs;
+    }
+};
+
+} // namespace
+
+static auto& g_properties_lock = *new std::mutex;
+static auto& g_properties = *new std::set<prop_info, prop_info_cmp>;
+
+static bool property_set(const char* key, const char* value) {
+    if (key == nullptr || *key == '\0') return false;
+    if (value == nullptr) value = "";
+    bool read_only = !strncmp(key, "ro.", 3);
+    if (!read_only && strlen(value) >= PROP_VALUE_MAX) return false;
+
+    std::lock_guard lock(g_properties_lock);
+    auto [it, success] = g_properties.emplace(key, value);
+    if (read_only) return success;
+    if (!success) {
+        it->value = value;
+        ++it->serial;
+    }
+    return true;
+}
+
+template <typename Func>
+static void property_get(const char* key, Func callback) {
+    std::lock_guard lock(g_properties_lock);
+    auto it = g_properties.find(key);
+    if (it != g_properties.end()) {
+        callback(*it);
+    }
+}
+
+// Redefine the __system_property_XXX functions here so we can perform
+// logging and access checks for all sysprops in native code.
+
+static void check_system_property_access(const char* key, bool write);
+
+extern "C" {
+
+int __system_property_set(const char* key, const char* value) {
+    check_system_property_access(key, true);
+    return property_set(key, value) ? 0 : -1;
+}
+
+int __system_property_get(const char* key, char* value) {
+    check_system_property_access(key, false);
+    *value = '\0';
+    property_get(key, [&](const prop_info& info) {
+        snprintf(value, PROP_VALUE_MAX, "%s", info.value.c_str());
+    });
+    return strlen(value);
+}
+
+const prop_info* __system_property_find(const char* key) {
+    check_system_property_access(key, false);
+    const prop_info* pi = nullptr;
+    property_get(key, [&](const prop_info& info) { pi = &info; });
+    return pi;
+}
+
+void __system_property_read_callback(const prop_info* pi,
+                                     void (*callback)(void*, const char*, const char*, uint32_t),
+                                     void* cookie) {
+    std::lock_guard lock(g_properties_lock);
+    callback(cookie, pi->key.c_str(), pi->value.c_str(), pi->serial);
+}
+
+} // extern "C"
+
+// ---- JNI ----
+
+static JavaVM* gVM = nullptr;
+static jclass gRunnerState = nullptr;
+static jmethodID gCheckSystemPropertyAccess;
+
+static void reloadNativeLibrary(JNIEnv* env, jclass, jstring javaPath) {
+    ScopedUtfChars path(env, javaPath);
+    // Force reload ourselves as global
+    dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL | RTLD_NOLOAD);
+}
+
+// Call back into Java code to check property access
+static void check_system_property_access(const char* key, bool write) {
+    if (gVM != nullptr && gRunnerState != nullptr) {
+        JNIEnv* env;
+        if (gVM->GetEnv((void**)&env, JNI_VERSION_1_4) >= 0) {
+            ALOGI("%s access to system property '%s'", write ? "Write" : "Read", key);
+            env->CallStaticVoidMethod(gRunnerState, gCheckSystemPropertyAccess,
+                                      env->NewStringUTF(key), write ? JNI_TRUE : JNI_FALSE);
+            return;
+        }
+    }
+    // Not on JVM thread, abort
+    LOG_ALWAYS_FATAL("Access to system property '%s' on non-JVM threads is not allowed.", key);
+}
+
+static jstring getSystemProperty(JNIEnv* env, jclass, jstring javaKey) {
+    ScopedUtfChars key(env, javaKey);
+    jstring value = nullptr;
+    property_get(key.c_str(),
+                 [&](const prop_info& info) { value = env->NewStringUTF(info.value.c_str()); });
+    return value;
+}
+
+static jboolean setSystemProperty(JNIEnv* env, jclass, jstring javaKey, jstring javaValue) {
+    ScopedUtfChars key(env, javaKey);
+    ScopedUtfChars value(env, javaValue);
+    return property_set(key.c_str(), value.c_str()) ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean removeSystemProperty(JNIEnv* env, jclass, jstring javaKey) {
+    std::lock_guard lock(g_properties_lock);
+
+    if (javaKey == nullptr) {
+        g_properties.clear();
+        return JNI_TRUE;
+    } else {
+        ScopedUtfChars key(env, javaKey);
+        auto it = g_properties.find(key);
+        if (it != g_properties.end()) {
+            g_properties.erase(it);
+            return JNI_TRUE;
+        } else {
+            return JNI_FALSE;
+        }
+    }
+}
+
 static void maybeRedirectLog() {
     auto ravenwoodLogOut = getenv("RAVENWOOD_LOG_OUT");
     if (ravenwoodLogOut == NULL) {
@@ -42,9 +200,30 @@
     dup2(ttyFd, 2);
 }
 
+static const JNINativeMethod sMethods[] = {
+        {"reloadNativeLibrary", "(Ljava/lang/String;)V", (void*)reloadNativeLibrary},
+        {"getSystemProperty", "(Ljava/lang/String;)Ljava/lang/String;", (void*)getSystemProperty},
+        {"setSystemProperty", "(Ljava/lang/String;Ljava/lang/String;)Z", (void*)setSystemProperty},
+        {"removeSystemProperty", "(Ljava/lang/String;)Z", (void*)removeSystemProperty},
+};
+
 extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) {
     ALOGI("%s: JNI_OnLoad", __FILE__);
 
     maybeRedirectLog();
+
+    JNIEnv* env = GetJNIEnvOrDie(vm);
+    gVM = vm;
+
+    // Fetch several references for future use
+    gRunnerState = FindGlobalClassOrDie(env, kRunnerState);
+    gCheckSystemPropertyAccess =
+            GetStaticMethodIDOrDie(env, gRunnerState, "checkSystemPropertyAccess",
+                                   "(Ljava/lang/String;Z)V");
+
+    // Expose raw property methods as JNI methods
+    jint res = jniRegisterNativeMethods(env, kRuntimeNative, sMethods, NELEM(sMethods));
+    if (res < 0) return -1;
+
     return JNI_VERSION_1_4;
 }
diff --git a/ravenwood/runtime-jni/ravenwood_runtime.cpp b/ravenwood/runtime-jni/ravenwood_runtime.cpp
index c1993f6..bab4c7e 100644
--- a/ravenwood/runtime-jni/ravenwood_runtime.cpp
+++ b/ravenwood/runtime-jni/ravenwood_runtime.cpp
@@ -174,6 +174,9 @@
     throwIfMinusOne(env, "setenv", setenv(name.c_str(), value.c_str(), overwrite ? 1 : 0));
 }
 
+static jint Linux_getpid(JNIEnv* env, jobject) {
+    return getpid();
+}
 
 static jint Linux_gettid(JNIEnv* env, jobject) {
     // gettid(2() was added in glibc 2.30 but Android uses an older version in prebuilt.
@@ -196,6 +199,7 @@
     { "stat", "(Ljava/lang/String;)Landroid/system/StructStat;", (void*)Linux_stat },
     { "nOpen", "(Ljava/lang/String;II)I", (void*)Linux_open },
     { "setenv", "(Ljava/lang/String;Ljava/lang/String;Z)V", (void*)Linux_setenv },
+    { "getpid", "()I", (void*)Linux_getpid },
     { "gettid", "()I", (void*)Linux_gettid },
 };
 
diff --git a/ravenwood/runtime-jni/ravenwood_sysprop.cpp b/ravenwood/runtime-jni/ravenwood_sysprop.cpp
deleted file mode 100644
index aafc426..0000000
--- a/ravenwood/runtime-jni/ravenwood_sysprop.cpp
+++ /dev/null
@@ -1,187 +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.
- */
-
-#include <dlfcn.h>
-
-#include <set>
-
-#include "jni_helper.h"
-
-// Implement a rudimentary system properties data store
-
-#define PROP_VALUE_MAX 92
-
-namespace {
-
-struct prop_info {
-    std::string key;
-    mutable std::string value;
-    mutable uint32_t serial;
-
-    prop_info(const char* key, const char* value) : key(key), value(value), serial(0) {}
-};
-
-struct prop_info_cmp {
-    using is_transparent = void;
-    bool operator()(const prop_info& lhs, const prop_info& rhs) {
-        return lhs.key < rhs.key;
-    }
-    bool operator()(std::string_view lhs, const prop_info& rhs) {
-        return lhs < rhs.key;
-    }
-    bool operator()(const prop_info& lhs, std::string_view rhs) {
-        return lhs.key < rhs;
-    }
-};
-
-} // namespace
-
-static auto& g_properties_lock = *new std::mutex;
-static auto& g_properties = *new std::set<prop_info, prop_info_cmp>;
-
-static bool property_set(const char* key, const char* value) {
-    if (key == nullptr || *key == '\0') return false;
-    if (value == nullptr) value = "";
-    bool read_only = !strncmp(key, "ro.", 3);
-    if (!read_only && strlen(value) >= PROP_VALUE_MAX) return false;
-
-    std::lock_guard lock(g_properties_lock);
-    auto [it, success] = g_properties.emplace(key, value);
-    if (read_only) return success;
-    if (!success) {
-        it->value = value;
-        ++it->serial;
-    }
-    return true;
-}
-
-template <typename Func>
-static void property_get(const char* key, Func callback) {
-    std::lock_guard lock(g_properties_lock);
-    auto it = g_properties.find(key);
-    if (it != g_properties.end()) {
-        callback(*it);
-    }
-}
-
-// Redefine the __system_property_XXX functions here so we can perform
-// logging and access checks for all sysprops in native code.
-
-static void check_system_property_access(const char* key, bool write);
-
-extern "C" {
-
-int __system_property_set(const char* key, const char* value) {
-    check_system_property_access(key, true);
-    return property_set(key, value) ? 0 : -1;
-}
-
-int __system_property_get(const char* key, char* value) {
-    check_system_property_access(key, false);
-    *value = '\0';
-    property_get(key, [&](const prop_info& info) {
-        snprintf(value, PROP_VALUE_MAX, "%s", info.value.c_str());
-    });
-    return strlen(value);
-}
-
-const prop_info* __system_property_find(const char* key) {
-    check_system_property_access(key, false);
-    const prop_info* pi = nullptr;
-    property_get(key, [&](const prop_info& info) { pi = &info; });
-    return pi;
-}
-
-void __system_property_read_callback(const prop_info* pi,
-                                     void (*callback)(void*, const char*, const char*, uint32_t),
-                                     void* cookie) {
-    std::lock_guard lock(g_properties_lock);
-    callback(cookie, pi->key.c_str(), pi->value.c_str(), pi->serial);
-}
-
-} // extern "C"
-
-// ---- JNI ----
-
-static JavaVM* gVM = nullptr;
-static jclass gEnvController = nullptr;
-static jmethodID gCheckSystemPropertyAccess;
-
-static void reloadNativeLibrary(JNIEnv* env, jclass, jstring javaPath) {
-    ScopedUtfChars path(env, javaPath);
-    // Force reload ourselves as global
-    dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL | RTLD_NOLOAD);
-}
-
-// Call back into Java code to check property access
-static void check_system_property_access(const char* key, bool write) {
-    if (gVM != nullptr && gEnvController != nullptr) {
-        JNIEnv* env;
-        if (gVM->GetEnv((void**)&env, JNI_VERSION_1_4) >= 0) {
-            ALOGI("%s access to system property '%s'", write ? "Write" : "Read", key);
-            env->CallStaticVoidMethod(gEnvController, gCheckSystemPropertyAccess,
-                                      env->NewStringUTF(key), write ? JNI_TRUE : JNI_FALSE);
-            return;
-        }
-    }
-    // Not on JVM thread, abort
-    LOG_ALWAYS_FATAL("Access to system property '%s' on non-JVM threads is not allowed.", key);
-}
-
-static jstring getSystemProperty(JNIEnv* env, jclass, jstring javaKey) {
-    ScopedUtfChars key(env, javaKey);
-    jstring value = nullptr;
-    property_get(key.c_str(),
-                 [&](const prop_info& info) { value = env->NewStringUTF(info.value.c_str()); });
-    return value;
-}
-
-static jboolean setSystemProperty(JNIEnv* env, jclass, jstring javaKey, jstring javaValue) {
-    ScopedUtfChars key(env, javaKey);
-    ScopedUtfChars value(env, javaValue);
-    return property_set(key.c_str(), value.c_str()) ? JNI_TRUE : JNI_FALSE;
-}
-
-static void clearSystemProperties(JNIEnv*, jclass) {
-    std::lock_guard lock(g_properties_lock);
-    g_properties.clear();
-}
-
-static const JNINativeMethod sMethods[] = {
-        {"reloadNativeLibrary", "(Ljava/lang/String;)V", (void*)reloadNativeLibrary},
-        {"getSystemProperty", "(Ljava/lang/String;)Ljava/lang/String;", (void*)getSystemProperty},
-        {"setSystemProperty", "(Ljava/lang/String;Ljava/lang/String;)Z", (void*)setSystemProperty},
-        {"clearSystemProperties", "()V", (void*)clearSystemProperties},
-};
-
-extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) {
-    ALOGI("%s: JNI_OnLoad", __FILE__);
-
-    JNIEnv* env = GetJNIEnvOrDie(vm);
-    gVM = vm;
-
-    // Fetch several references for future use
-    gEnvController = FindGlobalClassOrDie(env, kRuntimeEnvController);
-    gCheckSystemPropertyAccess =
-            GetStaticMethodIDOrDie(env, gEnvController, "checkSystemPropertyAccess",
-                                   "(Ljava/lang/String;Z)V");
-
-    // Expose raw property methods as JNI methods
-    jint res = jniRegisterNativeMethods(env, kRuntimeNative, sMethods, NELEM(sMethods));
-    if (res < 0) return -1;
-
-    return JNI_VERSION_1_4;
-}
diff --git a/ravenwood/test-authors.md b/ravenwood/test-authors.md
index c29fb7f..6d82a74 100644
--- a/ravenwood/test-authors.md
+++ b/ravenwood/test-authors.md
@@ -106,45 +106,6 @@
 
 > **Note:** There's a known bug #308854804 where `TEST_MAPPING` is not being applied, so we're currently planning to run all Ravenwood tests unconditionally in presubmit for changes to `frameworks/base/` and `cts/` until there is a better path forward.
 
-## Strategies for feature flags
-
-Ravenwood supports writing tests against logic that uses feature flags through the existing `SetFlagsRule` infrastructure maintained by the feature flagging team:
-
-```
-import android.platform.test.flag.junit.SetFlagsRule;
-
-@RunWith(AndroidJUnit4.class)
-public class MyCodeTest {
-    @Rule
-    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(SetFlagsRule.DefaultInitValueType.NULL_DEFAULT);
-
-    @Test
-    public void testEnabled() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_MY_FLAG);
-        // verify test logic that depends on flag being enabled
-    }
-```
-
-This naturally composes together well with any `RavenwoodRule` that your test may need.
-
-While `SetFlagsRule` is generally a best-practice (as it can explicitly confirm behaviors for both "on" and "off" states), you may need to write tests that use `CheckFlagsRule` (such as when writing CTS).  Ravenwood currently supports `CheckFlagsRule` by offering "all-on" and "all-off" behaviors:
-
-```
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
-import android.platform.test.flag.junit.RavenwoodFlagsValueProvider;
-import android.platform.test.ravenwood.RavenwoodRule;
-
-@RunWith(AndroidJUnit4.class)
-public class MyCodeTest {
-    @Rule
-    public final CheckFlagsRule mCheckFlagsRule = RavenwoodRule.isUnderRavenwood()
-            ? RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule()
-            : DeviceFlagsValueProvider.createCheckFlagsRule();
-```
-
-Ravenwood currently doesn't have knowledge of the "default" value of any flags, so using `createAllOnCheckFlagsRule()` is recommended to verify the widest possible set of behaviors.  The example code above falls back to using default values from `DeviceFlagsValueProvider` when not running on Ravenwood.
-
 ## Strategies for migration/bivalent tests
 
 Ravenwood aims to support tests that are written in a “bivalent” way, where the same test code can be dual-compiled to run on both a real Android device and under a Ravenwood environment.
diff --git a/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodMultipleRuleTest.java b/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodMultipleRuleTest.java
deleted file mode 100644
index c25d2b4..0000000
--- a/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodMultipleRuleTest.java
+++ /dev/null
@@ -1,57 +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.ravenwoodtest.bivalenttest;
-
-import android.platform.test.ravenwood.RavenwoodConfig;
-import android.platform.test.ravenwood.RavenwoodRule;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import org.junit.Assume;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-
-/**
- * Make sure having multiple RavenwoodRule's is detected.
- * (But only when running on ravenwod. Otherwise it'll be ignored.)
- */
-@RunWith(AndroidJUnit4.class)
-public class RavenwoodMultipleRuleTest {
-
-    @Rule(order = Integer.MIN_VALUE)
-    public final ExpectedException mExpectedException = ExpectedException.none();
-
-    @Rule
-    public final RavenwoodRule mRavenwood1 = new RavenwoodRule();
-
-    @Rule
-    public final RavenwoodRule mRavenwood2 = new RavenwoodRule();
-
-    public RavenwoodMultipleRuleTest() {
-        // We can't call it within the test method because the exception happens before
-        // calling the method, so set it up here.
-        if (RavenwoodConfig.isOnRavenwood()) {
-            mExpectedException.expectMessage("Multiple nesting RavenwoodRule");
-        }
-    }
-
-    @Test
-    public void testMultipleRulesNotAllowed() {
-        Assume.assumeTrue(RavenwoodConfig.isOnRavenwood());
-    }
-}
diff --git a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRuleValidationTest.java b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRuleValidationTest.java
new file mode 100644
index 0000000..f9e73db
--- /dev/null
+++ b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRuleValidationTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.ravenwoodtest.runnercallbacktests;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.SystemProperties;
+import android.platform.test.annotations.NoRavenizer;
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+
+/**
+ * Test for RavenwoodRule.
+ */
+@NoRavenizer // This class shouldn't be executed with RavenwoodAwareTestRunner.
+public class RavenwoodRuleValidationTest extends RavenwoodRunnerTestBase {
+
+    public static class RuleInBaseClass {
+        static String PROPERTY_KEY = "debug.ravenwood.prop.in.base";
+        static String PROPERTY_VAL = "ravenwood";
+        @Rule
+        public final RavenwoodRule mRavenwood1 = new RavenwoodRule.Builder()
+                .setSystemPropertyImmutable(PROPERTY_KEY, PROPERTY_VAL).build();
+    }
+
+    /**
+     * Make sure that RavenwoodRule in a base class takes effect.
+     */
+    @RunWith(AndroidJUnit4.class)
+    // CHECKSTYLE:OFF
+    @Expected("""
+    testRunStarted: classes
+    testSuiteStarted: classes
+    testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRuleValidationTest$RuleInBaseClassSuccessTest
+    testStarted: testRuleInBaseClass(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRuleValidationTest$RuleInBaseClassSuccessTest)
+    testFinished: testRuleInBaseClass(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRuleValidationTest$RuleInBaseClassSuccessTest)
+    testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRuleValidationTest$RuleInBaseClassSuccessTest
+    testSuiteFinished: classes
+    testRunFinished: 1,0,0,0
+    """)
+    // CHECKSTYLE:ON
+    public static class RuleInBaseClassSuccessTest extends RuleInBaseClass {
+
+        @Test
+        public void testRuleInBaseClass() {
+            assertThat(SystemProperties.get(PROPERTY_KEY)).isEqualTo(PROPERTY_VAL);
+        }
+    }
+
+    /**
+     * Same as {@link RuleInBaseClass}, but the type of the rule field is not {@link RavenwoodRule}.
+     */
+    public abstract static class RuleWithDifferentTypeInBaseClass {
+        static String PROPERTY_KEY = "debug.ravenwood.prop.in.base.different.type";
+        static String PROPERTY_VAL = "ravenwood";
+        @Rule
+        public final TestRule mRavenwood1 = new RavenwoodRule.Builder()
+                .setSystemPropertyImmutable(PROPERTY_KEY, PROPERTY_VAL).build();
+    }
+
+    /**
+     * Make sure that RavenwoodRule in a base class takes effect, even if the field type is not
+     */
+    @RunWith(AndroidJUnit4.class)
+    // CHECKSTYLE:OFF
+    @Expected("""
+    testRunStarted: classes
+    testSuiteStarted: classes
+    testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRuleValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest
+    testStarted: testRuleInBaseClass(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRuleValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest)
+    testFinished: testRuleInBaseClass(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRuleValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest)
+    testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRuleValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest
+    testSuiteFinished: classes
+    testRunFinished: 1,0,0,0
+    """)
+    // CHECKSTYLE:ON
+    public static class RuleWithDifferentTypeInBaseClassSuccessTest extends RuleWithDifferentTypeInBaseClass {
+
+        @Test
+        public void testRuleInBaseClass() {
+            assertThat(SystemProperties.get(PROPERTY_KEY)).isEqualTo(PROPERTY_VAL);
+        }
+    }
+}
diff --git a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerConfigValidationTest.java b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerConfigValidationTest.java
deleted file mode 100644
index f94b98b..0000000
--- a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerConfigValidationTest.java
+++ /dev/null
@@ -1,484 +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.ravenwoodtest.runnercallbacktests;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.platform.test.annotations.NoRavenizer;
-import android.platform.test.ravenwood.RavenwoodConfig;
-import android.platform.test.ravenwood.RavenwoodRule;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestRule;
-import org.junit.runner.RunWith;
-
-
-/**
- * Test for @Config field extraction and validation.
- *
- * TODO(b/377765941) Most of the tests here will be obsolete and deleted with b/377765941, but
- * some of the tests may need to be re-implemented one way or another. (e.g. the package name
- * test.) Until that happens, we'll keep all tests here but add an {@code @Ignore} instead.
- */
-@NoRavenizer // This class shouldn't be executed with RavenwoodAwareTestRunner.
-public class RavenwoodRunnerConfigValidationTest extends RavenwoodRunnerTestBase {
-    public abstract static class ConfigInBaseClass {
-        static String PACKAGE_NAME = "com.ConfigInBaseClass";
-
-        @RavenwoodConfig.Config
-        public static RavenwoodConfig sConfig = new RavenwoodConfig.Builder()
-                .setPackageName(PACKAGE_NAME).build();
-    }
-
-    /**
-     * Make sure a config in the base class is detected.
-     */
-    @RunWith(AndroidJUnit4.class)
-    // CHECKSTYLE:OFF
-    @Expected("""
-    testRunStarted: classes
-    testSuiteStarted: classes
-    testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigInBaseClassTest
-    testStarted: test(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigInBaseClassTest)
-    testFinished: test(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigInBaseClassTest)
-    testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigInBaseClassTest
-    testSuiteFinished: classes
-    testRunFinished: 1,0,0,0
-    """)
-    // CHECKSTYLE:ON
-    @Ignore // Package name is no longer set via config.
-    public static class ConfigInBaseClassTest extends ConfigInBaseClass {
-        @Test
-        public void test() {
-            assertThat(InstrumentationRegistry.getInstrumentation().getContext().getPackageName())
-                    .isEqualTo(PACKAGE_NAME);
-        }
-    }
-
-    /**
-     * Make sure a config in the base class is detected.
-     */
-    @RunWith(AndroidJUnit4.class)
-    // CHECKSTYLE:OFF
-    @Expected("""
-    testRunStarted: classes
-    testSuiteStarted: classes
-    testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigOverridingTest
-    testStarted: test(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigOverridingTest)
-    testFinished: test(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigOverridingTest)
-    testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigOverridingTest
-    testSuiteFinished: classes
-    testRunFinished: 1,0,0,0
-    """)
-    // CHECKSTYLE:ON
-    @Ignore // Package name is no longer set via config.
-    public static class ConfigOverridingTest extends ConfigInBaseClass {
-        static String PACKAGE_NAME_OVERRIDE = "com.ConfigOverridingTest";
-
-        @RavenwoodConfig.Config
-        public static RavenwoodConfig sConfig = new RavenwoodConfig.Builder()
-                .setPackageName(PACKAGE_NAME_OVERRIDE).build();
-
-        @Test
-        public void test() {
-            assertThat(InstrumentationRegistry.getInstrumentation().getContext().getPackageName())
-                    .isEqualTo(PACKAGE_NAME_OVERRIDE);
-        }
-    }
-
-    /**
-     * Test to make sure that if a test has a config error, the failure would be reported from
-     * each test method.
-     */
-    @RunWith(AndroidJUnit4.class)
-    // CHECKSTYLE:OFF
-    @Expected("""
-    testRunStarted: classes
-    testSuiteStarted: classes
-    testStarted: initializationError(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ErrorMustBeReportedFromEachTest)
-    testFailure: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ErrorMustBeReportedFromEachTest.sConfig expected to be public static
-    testFinished: initializationError(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ErrorMustBeReportedFromEachTest)
-    testSuiteFinished: classes
-    testRunFinished: 1,1,0,0
-    """)
-    // CHECKSTYLE:ON
-    public static class ErrorMustBeReportedFromEachTest {
-        @RavenwoodConfig.Config
-        private static RavenwoodConfig sConfig = // Invalid because it's private.
-                new RavenwoodConfig.Builder().build();
-
-        @Test
-        public void testMethod1() {
-        }
-
-        @Test
-        public void testMethod2() {
-        }
-
-        @Test
-        public void testMethod3() {
-        }
-    }
-
-    /**
-     * Invalid because there are two @Config's.
-     */
-    @RunWith(AndroidJUnit4.class)
-    // CHECKSTYLE:OFF
-    @Expected("""
-    testRunStarted: classes
-    testSuiteStarted: classes
-    testStarted: initializationError(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$DuplicateConfigTest)
-    testFailure: Class com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest.DuplicateConfigTest has multiple fields with @RavenwoodConfig.Config
-    testFinished: initializationError(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$DuplicateConfigTest)
-    testSuiteFinished: classes
-    testRunFinished: 1,1,0,0
-    """)
-    // CHECKSTYLE:ON
-    public static class DuplicateConfigTest {
-
-        @RavenwoodConfig.Config
-        public static RavenwoodConfig sConfig1 =
-                new RavenwoodConfig.Builder().build();
-
-        @RavenwoodConfig.Config
-        public static RavenwoodConfig sConfig2 =
-                new RavenwoodConfig.Builder().build();
-
-        @Test
-        public void testConfig() {
-        }
-    }
-
-    /**
-     * @Config's must be static.
-     */
-    @RunWith(AndroidJUnit4.class)
-    // CHECKSTYLE:OFF
-    @Expected("""
-    testRunStarted: classes
-    testSuiteStarted: classes
-    testStarted: initializationError(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$NonStaticConfigTest)
-    testFailure: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$NonStaticConfigTest.sConfig expected to be public static
-    testFinished: initializationError(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$NonStaticConfigTest)
-    testSuiteFinished: classes
-    testRunFinished: 1,1,0,0
-    """)
-    // CHECKSTYLE:ON
-    public static class NonStaticConfigTest {
-
-        @RavenwoodConfig.Config
-        public RavenwoodConfig sConfig =
-                new RavenwoodConfig.Builder().build();
-
-        @Test
-        public void testConfig() {
-        }
-    }
-
-    /**
-     * @Config's must be public.
-     */
-    @RunWith(AndroidJUnit4.class)
-    // CHECKSTYLE:OFF
-    @Expected("""
-    testRunStarted: classes
-    testSuiteStarted: classes
-    testStarted: initializationError(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$NonPublicConfigTest)
-    testFailure: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$NonPublicConfigTest.sConfig expected to be public static
-    testFinished: initializationError(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$NonPublicConfigTest)
-    testSuiteFinished: classes
-    testRunFinished: 1,1,0,0
-    """)
-    // CHECKSTYLE:ON
-    public static class NonPublicConfigTest {
-
-        @RavenwoodConfig.Config
-        RavenwoodConfig sConfig =
-                new RavenwoodConfig.Builder().build();
-
-        @Test
-        public void testConfig() {
-        }
-    }
-
-    /**
-     * @Config's must be of type RavenwoodConfig.
-     */
-    @RunWith(AndroidJUnit4.class)
-    // CHECKSTYLE:OFF
-    @Expected("""
-    testRunStarted: classes
-    testSuiteStarted: classes
-    testStarted: initializationError(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WrongTypeConfigTest)
-    testFailure: Field com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest.WrongTypeConfigTest.sConfig has @RavenwoodConfig.Config but type is not RavenwoodConfig
-    testFinished: initializationError(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WrongTypeConfigTest)
-    testSuiteFinished: classes
-    testRunFinished: 1,1,0,0
-    """)
-    // CHECKSTYLE:ON
-    public static class WrongTypeConfigTest {
-
-        @RavenwoodConfig.Config
-        public static Object sConfig =
-                new RavenwoodConfig.Builder().build();
-
-        @Test
-        public void testConfig() {
-        }
-
-    }
-
-    /**
-     * @Rule must be of type RavenwoodRule.
-     */
-    @RunWith(AndroidJUnit4.class)
-    // CHECKSTYLE:OFF
-    @Expected("""
-    testRunStarted: classes
-    testSuiteStarted: classes
-    testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WrongTypeRuleTest
-    testStarted: testConfig(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WrongTypeRuleTest)
-    testFailure: If you have a RavenwoodRule in your test, make sure the field type is RavenwoodRule so Ravenwood can detect it.
-    testFinished: testConfig(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WrongTypeRuleTest)
-    testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WrongTypeRuleTest
-    testSuiteFinished: classes
-    testRunFinished: 1,1,0,0
-    """)
-    // CHECKSTYLE:ON
-    public static class WrongTypeRuleTest {
-
-        @Rule
-        public TestRule mRule = new RavenwoodRule.Builder().build();
-
-        @Test
-        public void testConfig() {
-        }
-
-    }
-
-    /**
-     * Config can't be used with a (instance) Rule.
-     */
-    @RunWith(AndroidJUnit4.class)
-    // CHECKSTYLE:OFF
-    @Expected("""
-    testRunStarted: classes
-    testSuiteStarted: classes
-    testStarted: initializationError(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WithInstanceRuleTest)
-    testFailure: RavenwoodConfig and RavenwoodRule cannot be used in the same class. Suggest migrating to RavenwoodConfig.
-    testFinished: initializationError(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WithInstanceRuleTest)
-    testSuiteFinished: classes
-    testRunFinished: 1,1,0,0
-    """)
-    // CHECKSTYLE:ON
-    public static class WithInstanceRuleTest {
-
-        @RavenwoodConfig.Config
-        public static RavenwoodConfig sConfig =
-                new RavenwoodConfig.Builder().build();
-
-        @Rule
-        public RavenwoodRule mRule = new RavenwoodRule.Builder().build();
-
-        @Test
-        public void testConfig() {
-        }
-    }
-
-    /**
-     * Config can't be used with a (static) Rule.
-     */
-    @RunWith(AndroidJUnit4.class)
-    // CHECKSTYLE:OFF
-    @Expected("""
-    testRunStarted: classes
-    testSuiteStarted: classes
-    testStarted: initializationError(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WithStaticRuleTest)
-    testFailure: Failed to instantiate class androidx.test.ext.junit.runners.AndroidJUnit4
-    testFinished: initializationError(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WithStaticRuleTest)
-    testSuiteFinished: classes
-    testRunFinished: 1,1,0,0
-    """)
-    // CHECKSTYLE:ON
-    public static class WithStaticRuleTest {
-
-        @RavenwoodConfig.Config
-        public static RavenwoodConfig sConfig =
-                new RavenwoodConfig.Builder().build();
-
-        @Rule
-        public static RavenwoodRule sRule = new RavenwoodRule.Builder().build();
-
-        @Test
-        public void testConfig() {
-        }
-    }
-
-    @RunWith(AndroidJUnit4.class)
-    // CHECKSTYLE:OFF
-    @Expected("""
-    testRunStarted: classes
-    testSuiteStarted: classes
-    testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$DuplicateRulesTest
-    testStarted: testMultipleRulesNotAllowed(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$DuplicateRulesTest)
-    testFailure: Multiple nesting RavenwoodRule's are detected in the same class, which is not supported.
-    testFinished: testMultipleRulesNotAllowed(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$DuplicateRulesTest)
-    testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$DuplicateRulesTest
-    testSuiteFinished: classes
-    testRunFinished: 1,1,0,0
-    """)
-    // CHECKSTYLE:ON
-    public static class DuplicateRulesTest {
-
-        @Rule
-        public final RavenwoodRule mRavenwood1 = new RavenwoodRule();
-
-        @Rule
-        public final RavenwoodRule mRavenwood2 = new RavenwoodRule();
-
-        @Test
-        public void testMultipleRulesNotAllowed() {
-        }
-    }
-
-    public static class RuleInBaseClass {
-        static String PACKAGE_NAME = "com.RuleInBaseClass";
-        @Rule
-        public final RavenwoodRule mRavenwood1 = new RavenwoodRule.Builder()
-                .setPackageName(PACKAGE_NAME).build();
-    }
-
-    /**
-     * Make sure that RavenwoodRule in a base class takes effect.
-     */
-    @RunWith(AndroidJUnit4.class)
-    // CHECKSTYLE:OFF
-    @Expected("""
-    testRunStarted: classes
-    testSuiteStarted: classes
-    testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$RuleInBaseClassSuccessTest
-    testStarted: testRuleInBaseClass(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$RuleInBaseClassSuccessTest)
-    testFinished: testRuleInBaseClass(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$RuleInBaseClassSuccessTest)
-    testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$RuleInBaseClassSuccessTest
-    testSuiteFinished: classes
-    testRunFinished: 1,0,0,0
-    """)
-    // CHECKSTYLE:ON
-    @Ignore // Package name is no longer set via config.
-    public static class RuleInBaseClassSuccessTest extends RuleInBaseClass {
-
-        @Test
-        public void testRuleInBaseClass() {
-            assertThat(InstrumentationRegistry.getInstrumentation().getContext().getPackageName())
-                    .isEqualTo(PACKAGE_NAME);
-        }
-    }
-
-    /**
-     * Make sure that having a config and a rule in a base class should fail.
-     * RavenwoodRule.
-     */
-    @RunWith(AndroidJUnit4.class)
-    // CHECKSTYLE:OFF
-    @Expected("""
-    testRunStarted: classes
-    testSuiteStarted: classes
-    testStarted: initializationError(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigWithRuleInBaseClassTest)
-    testFailure: RavenwoodConfig and RavenwoodRule cannot be used in the same class. Suggest migrating to RavenwoodConfig.
-    testFinished: initializationError(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigWithRuleInBaseClassTest)
-    testSuiteFinished: classes
-    testRunFinished: 1,1,0,0
-    """)
-    // CHECKSTYLE:ON
-    public static class ConfigWithRuleInBaseClassTest extends RuleInBaseClass {
-        @RavenwoodConfig.Config
-        public static RavenwoodConfig sConfig = new RavenwoodConfig.Builder().build();
-
-        @Test
-        public void test() {
-        }
-    }
-
-    /**
-     * Same as {@link RuleInBaseClass}, but the type of the rule field is not {@link RavenwoodRule}.
-     */
-    public abstract static class RuleWithDifferentTypeInBaseClass {
-        static String PACKAGE_NAME = "com.RuleWithDifferentTypeInBaseClass";
-        @Rule
-        public final TestRule mRavenwood1 = new RavenwoodRule.Builder()
-                .setPackageName(PACKAGE_NAME).build();
-    }
-
-    /**
-     * Make sure that RavenwoodRule in a base class takes effect, even if the field type is not
-     */
-    @RunWith(AndroidJUnit4.class)
-    // CHECKSTYLE:OFF
-    @Expected("""
-    testRunStarted: classes
-    testSuiteStarted: classes
-    testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest
-    testStarted: testRuleInBaseClass(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest)
-    testFailure: If you have a RavenwoodRule in your test, make sure the field type is RavenwoodRule so Ravenwood can detect it.
-    testFinished: testRuleInBaseClass(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest)
-    testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest
-    testSuiteFinished: classes
-    testRunFinished: 1,1,0,0
-    """)
-    // CHECKSTYLE:ON
-    @Ignore // Package name is no longer set via config.
-    public static class RuleWithDifferentTypeInBaseClassSuccessTest extends RuleWithDifferentTypeInBaseClass {
-
-        @Test
-        public void testRuleInBaseClass() {
-            assertThat(InstrumentationRegistry.getInstrumentation().getContext().getPackageName())
-                    .isEqualTo(PACKAGE_NAME);
-        }
-    }
-
-    /**
-     * Make sure that having a config and a rule in a base class should fail, even if the field type is not
-     * RavenwoodRule.
-     */
-    @RunWith(AndroidJUnit4.class)
-    // CHECKSTYLE:OFF
-    @Expected("""
-    testRunStarted: classes
-    testSuiteStarted: classes
-    testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigWithRuleWithDifferentTypeInBaseClassTest
-    testStarted: test(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigWithRuleWithDifferentTypeInBaseClassTest)
-    testFailure: If you have a RavenwoodRule in your test, make sure the field type is RavenwoodRule so Ravenwood can detect it.
-    testFinished: test(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigWithRuleWithDifferentTypeInBaseClassTest)
-    testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigWithRuleWithDifferentTypeInBaseClassTest
-    testSuiteFinished: classes
-    testRunFinished: 1,1,0,0
-    """)
-    // CHECKSTYLE:ON
-    public static class ConfigWithRuleWithDifferentTypeInBaseClassTest extends RuleWithDifferentTypeInBaseClass {
-        @RavenwoodConfig.Config
-        public static RavenwoodConfig sConfig = new RavenwoodConfig.Builder().build();
-
-        @Test
-        public void test() {
-        }
-    }
-}
diff --git a/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/IdentityTest.java b/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/IdentityTest.java
index 8e04b69..271c27f 100644
--- a/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/IdentityTest.java
+++ b/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/IdentityTest.java
@@ -15,7 +15,6 @@
  */
 package com.android.ravenwoodtest.runtimetest;
 
-import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
 import static android.os.Process.FIRST_APPLICATION_UID;
 
 import static org.junit.Assert.assertEquals;
@@ -23,7 +22,6 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Process;
-import android.platform.test.ravenwood.RavenwoodConfig;
 import android.system.Os;
 
 import com.android.ravenwood.RavenwoodRuntimeState;
@@ -34,13 +32,6 @@
 
 public class IdentityTest {
 
-    @RavenwoodConfig.Config
-    public static final RavenwoodConfig sConfig =
-            new RavenwoodConfig.Builder()
-                    .setTargetSdkLevel(UPSIDE_DOWN_CAKE)
-                    .setProcessApp()
-                    .build();
-
     @Test
     public void testUid() {
         assertEquals(FIRST_APPLICATION_UID, RavenwoodRuntimeState.sUid);
@@ -60,7 +51,7 @@
     @Test
     public void testTargetSdkLevel() {
         assertEquals(Build.VERSION_CODES.CUR_DEVELOPMENT, RavenwoodRuntimeState.CUR_DEVELOPMENT);
-        assertEquals(UPSIDE_DOWN_CAKE, RavenwoodRuntimeState.sTargetSdkLevel);
-        assertEquals(UPSIDE_DOWN_CAKE, VMRuntime.getRuntime().getTargetSdkVersion());
+        assertEquals(RavenwoodRuntimeState.sTargetSdkLevel,
+                VMRuntime.getRuntime().getTargetSdkVersion());
     }
 }
diff --git a/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/SystemPropertyTest.java b/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/SystemPropertyTest.java
new file mode 100644
index 0000000..70bf204
--- /dev/null
+++ b/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/SystemPropertyTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.ravenwoodtest.runtimetest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.SystemProperties;
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.Statement;
+
+public class SystemPropertyTest {
+
+    private static final String PROP_KEY_1 = "debug.ravenwood.prop1";
+    private static final String PROP_VAL_1 = "ravenwood.1";
+    private static final String PROP_KEY_2 = "debug.ravenwood.prop2";
+    private static final String PROP_VAL_2 = "ravenwood.2";
+    private static final String PROP_KEY_3 = "debug.ravenwood.prop3";
+    private static final String PROP_VAL_3 = "ravenwood.3";
+    private static final String PROP_VAL_4 = "ravenwood.4";
+
+    @ClassRule(order = 0)
+    public static TestRule mCheckClassRule = (base, description) -> new Statement() {
+        @Override
+        public void evaluate() throws Throwable {
+            assertTrue(SystemProperties.get(PROP_KEY_1).isEmpty());
+            assertTrue(SystemProperties.get(PROP_KEY_3).isEmpty());
+            try {
+                base.evaluate();
+            } finally {
+                assertTrue(SystemProperties.get(PROP_KEY_1).isEmpty());
+                assertTrue(SystemProperties.get(PROP_KEY_3).isEmpty());
+            }
+        }
+    };
+
+    @ClassRule(order = 1)
+    public static RavenwoodRule mClassRule = new RavenwoodRule.Builder()
+            .setSystemPropertyImmutable(PROP_KEY_1, PROP_VAL_1)
+            .setSystemPropertyImmutable(PROP_KEY_3, PROP_VAL_4)
+            .build();
+
+    @Rule(order = 0)
+    public TestRule mCheckRule = (base, description) -> new Statement() {
+        @Override
+        public void evaluate() throws Throwable {
+            assertTrue(SystemProperties.get(PROP_KEY_2).isEmpty());
+            assertEquals(SystemProperties.get(PROP_KEY_3), PROP_VAL_4);
+            try {
+                base.evaluate();
+            } finally {
+                assertTrue(SystemProperties.get(PROP_KEY_2).isEmpty());
+                assertEquals(SystemProperties.get(PROP_KEY_3), PROP_VAL_4);
+            }
+        }
+    };
+
+    @Rule(order = 1)
+    public RavenwoodRule mRule = new RavenwoodRule.Builder()
+            .setSystemPropertyImmutable(PROP_KEY_2, PROP_VAL_2)
+            .setSystemPropertyImmutable(PROP_KEY_3, PROP_VAL_3)
+            .build();
+
+    @Test
+    public void testRavenwoodRuleSetProperty() {
+        assertEquals(SystemProperties.get(PROP_KEY_1), PROP_VAL_1);
+        assertEquals(SystemProperties.get(PROP_KEY_2), PROP_VAL_2);
+        assertEquals(SystemProperties.get(PROP_KEY_3), PROP_VAL_3);
+    }
+}
diff --git a/ravenwood/tests/services-test/test/com/android/ravenwoodtest/servicestest/RavenwoodServicesTest.java b/ravenwood/tests/services-test/test/com/android/ravenwoodtest/servicestest/RavenwoodServicesTest.java
index 4aae1e1..e83a247 100644
--- a/ravenwood/tests/services-test/test/com/android/ravenwoodtest/servicestest/RavenwoodServicesTest.java
+++ b/ravenwood/tests/services-test/test/com/android/ravenwoodtest/servicestest/RavenwoodServicesTest.java
@@ -24,8 +24,6 @@
 import android.content.Context;
 import android.hardware.SerialManager;
 import android.hardware.SerialManagerInternal;
-import android.platform.test.ravenwood.RavenwoodConfig;
-import android.platform.test.ravenwood.RavenwoodConfig.Config;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -42,12 +40,6 @@
 public class RavenwoodServicesTest {
     private static final String TEST_VIRTUAL_PORT = "virtual:example";
 
-    @Config
-    public static final RavenwoodConfig sRavenwood = new RavenwoodConfig.Builder()
-            .setProcessSystem()
-            .setServicesRequired(SerialManager.class)
-            .build();
-
     private Context mContext;
 
     @Before
diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/Android.bp b/ravenwood/tools/hoststubgen/test-tiny-framework/Android.bp
index 1570549..483c4be 100644
--- a/ravenwood/tools/hoststubgen/test-tiny-framework/Android.bp
+++ b/ravenwood/tools/hoststubgen/test-tiny-framework/Android.bp
@@ -156,6 +156,7 @@
     ],
     data: [
         "golden-output/*.txt",
+        "golden-output.RELEASE_TARGET_JAVA_21/*.txt",
     ],
     java_data: [
         "hoststubgen-test-tiny-framework-orig-dump",
diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/01-hoststubgen-test-tiny-framework-orig-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/01-hoststubgen-test-tiny-framework-orig-dump.txt
new file mode 100644
index 0000000..5e5ca62
--- /dev/null
+++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/01-hoststubgen-test-tiny-framework-orig-dump.txt
@@ -0,0 +1,3697 @@
+## Class: android/hosttest/annotation/HostSideTestClassLoadHook.class
+  Compiled from "HostSideTestClassLoadHook.java"
+public interface android.hosttest.annotation.HostSideTestClassLoadHook extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestClassLoadHook
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  public abstract java.lang.String value();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestClassLoadHook.java"
+RuntimeVisibleAnnotations:
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestIgnore.class
+  Compiled from "HostSideTestIgnore.java"
+public interface android.hosttest.annotation.HostSideTestIgnore extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestIgnore
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestIgnore.java"
+RuntimeVisibleAnnotations:
+  x: #x(#x=[e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestKeep.class
+  Compiled from "HostSideTestKeep.java"
+public interface android.hosttest.annotation.HostSideTestKeep extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestKeep
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestKeep.java"
+RuntimeVisibleAnnotations:
+  x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestRedirect.class
+  Compiled from "HostSideTestRedirect.java"
+public interface android.hosttest.annotation.HostSideTestRedirect extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestRedirect
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestRedirect.java"
+RuntimeVisibleAnnotations:
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestRedirectionClass.class
+  Compiled from "HostSideTestRedirectionClass.java"
+public interface android.hosttest.annotation.HostSideTestRedirectionClass extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestRedirectionClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  public abstract java.lang.String value();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestRedirectionClass.java"
+RuntimeVisibleAnnotations:
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestRemove.class
+  Compiled from "HostSideTestRemove.java"
+public interface android.hosttest.annotation.HostSideTestRemove extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestRemove
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestRemove.java"
+RuntimeVisibleAnnotations:
+  x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestStaticInitializerKeep.class
+  Compiled from "HostSideTestStaticInitializerKeep.java"
+public interface android.hosttest.annotation.HostSideTestStaticInitializerKeep extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestStaticInitializerKeep
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestStaticInitializerKeep.java"
+RuntimeVisibleAnnotations:
+  x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestSubstitute.class
+  Compiled from "HostSideTestSubstitute.java"
+public interface android.hosttest.annotation.HostSideTestSubstitute extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestSubstitute
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  public abstract java.lang.String suffix();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestSubstitute.java"
+RuntimeVisibleAnnotations:
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestThrow.class
+  Compiled from "HostSideTestThrow.java"
+public interface android.hosttest.annotation.HostSideTestThrow extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestThrow
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestThrow.java"
+RuntimeVisibleAnnotations:
+  x: #x(#x=[e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestWholeClassKeep.class
+  Compiled from "HostSideTestWholeClassKeep.java"
+public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestWholeClassKeep
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestWholeClassKeep.java"
+RuntimeVisibleAnnotations:
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/tests/HostSideTestSuppress.class
+  Compiled from "HostSideTestSuppress.java"
+public interface android.hosttest.annotation.tests.HostSideTestSuppress extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/tests/HostSideTestSuppress
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestSuppress.java"
+RuntimeVisibleAnnotations:
+  x: #x(#x=[e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD]
+    )
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy.class
+  Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy;
+
+  public static int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: iload_0
+         x: iconst_2
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0     a   I
+}
+SourceFile: "IPretendingAidl.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+InnerClasses:
+  public static #x= #x of #x;          // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub.class
+  Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub;
+
+  public static int addOne(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: iload_0
+         x: iconst_1
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0     a   I
+}
+SourceFile: "IPretendingAidl.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+InnerClasses:
+  public static #x= #x of #x;           // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl.class
+  Compiled from "IPretendingAidl.java"
+public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl
+  minor version: 0
+  major version: 65
+  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 0, attributes: 3
+}
+SourceFile: "IPretendingAidl.java"
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+InnerClasses:
+  public static #x= #x of #x;            // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class
+  Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R$Nested
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/R$Nested
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 3
+  public static int[] ARRAY;
+    descriptor: [I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+
+  public com.android.hoststubgen.test.tinyframework.R$Nested();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/R$Nested;
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: iconst_1
+         x: newarray       int
+         x: dup
+         x: iconst_0
+         x: iconst_1
+         x: iastore
+         x: putstatic     #x                  // Field ARRAY:[I
+        x: return
+      LineNumberTable:
+}
+SourceFile: "R.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/R
+InnerClasses:
+  public static #x= #x of #x;           // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/R.class
+  Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/R
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.R();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/R;
+}
+SourceFile: "R.java"
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/R$Nested
+InnerClasses:
+  public static #x= #x of #x;           // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.class
+  Compiled from "TinyFrameworkAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 9, attributes: 2
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public int remove;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: iconst_1
+         x: putfield      #x                  // Field keep:I
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: iload_1
+         x: iconst_1
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+            0       4     1 value   I
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public void toBeRemoved(java.lang.String);
+    descriptor: (Ljava/lang/String;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+            0       8     1   foo   Ljava/lang/String;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRemove
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String not supported on host side
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+            0      10     1 value   I
+    RuntimeInvisibleAnnotations:
+      x: #x(#x=s#x)
+        android.hosttest.annotation.HostSideTestSubstitute(
+          suffix="_host"
+        )
+
+  public int addTwo_host(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: iload_1
+         x: iconst_2
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+            0       4     1 value   I
+
+  public static native int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+    RuntimeInvisibleAnnotations:
+      x: #x(#x=s#x)
+        android.hosttest.annotation.HostSideTestSubstitute(
+          suffix="_host"
+        )
+
+  private static int nativeAddThree_host(int);
+    descriptor: (I)I
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: iload_0
+         x: iconst_3
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0 value   I
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: ldc           #x                 // String This value shouldn\'t be seen on the host side.
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       3     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestThrow
+
+  public int toBeIgnored();
+    descriptor: ()I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String not supported on host side
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestIgnore
+}
+SourceFile: "TinyFrameworkAnnotations.java"
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+  x: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
+  Compiled from "TinyFrameworkClassLoadHook.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 3, attributes: 2
+  public static final java.util.Set<java.lang.Class<?>> sLoadedClasses;
+    descriptor: Ljava/util/Set;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/Set<Ljava/lang/Class<*>;>;
+
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook();
+    descriptor: ()V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook;
+
+  public static void onClassLoaded(java.lang.Class<?>);
+    descriptor: (Ljava/lang/Class;)V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: getstatic     #x                  // Field sLoadedClasses:Ljava/util/Set;
+         x: aload_0
+         x: invokeinterface #x,  2           // InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z
+         x: pop
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0 clazz   Ljava/lang/Class;
+      LocalVariableTypeTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0 clazz   Ljava/lang/Class<*>;
+    Signature: #x                          // (Ljava/lang/Class<*>;)V
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: new           #x                 // class java/util/HashSet
+         x: dup
+         x: invokespecial #x                 // Method java/util/HashSet."<init>":()V
+         x: putstatic     #x                  // Field sLoadedClasses:Ljava/util/Set;
+        x: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkClassLoadHook.java"
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations.class
+  Compiled from "TinyFrameworkClassWideAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 6, attributes: 2
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public int remove;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRemove
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: iconst_1
+         x: putfield      #x                  // Field keep:I
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: iload_1
+         x: iconst_1
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+            0       4     1 value   I
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String not supported on host side
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+            0      10     1 value   I
+    RuntimeInvisibleAnnotations:
+      x: #x(#x=s#x)
+        android.hosttest.annotation.HostSideTestSubstitute(
+          suffix="_host"
+        )
+
+  public int addTwo_host(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: iload_1
+         x: iconst_2
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+            0       4     1 value   I
+
+  public void toBeRemoved(java.lang.String);
+    descriptor: (Ljava/lang/String;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+            0       8     1   foo   Ljava/lang/String;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRemove
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: ldc           #x                 // String This value shouldn\'t be seen on the host side.
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       3     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestThrow
+}
+SourceFile: "TinyFrameworkClassWideAnnotations.java"
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.class
+  Compiled from "TinyFrameworkClassWithInitializerDefault.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 2, attributes: 2
+  public static boolean sInitialized;
+    descriptor: Z
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static java.lang.Object sObject;
+    descriptor: Ljava/lang/Object;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault;
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: iconst_1
+         x: putstatic     #x                  // Field sInitialized:Z
+         x: new           #x                  // class java/lang/Object
+         x: dup
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+        x: putstatic     #x                 // Field sObject:Ljava/lang/Object;
+        x: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkClassWithInitializerDefault.java"
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub.class
+  Compiled from "TinyFrameworkClassWithInitializerStub.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerStub
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 2, attributes: 2
+  public static boolean sInitialized;
+    descriptor: Z
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static java.lang.Object sObject;
+    descriptor: Ljava/lang/Object;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerStub();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub;
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: iconst_1
+         x: putstatic     #x                  // Field sInitialized:Z
+         x: new           #x                  // class java/lang/Object
+         x: dup
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+        x: putstatic     #x                 // Field sObject:Ljava/lang/Object;
+        x: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkClassWithInitializerStub.java"
+RuntimeInvisibleAnnotations:
+  x: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+  x: #x()
+    android.hosttest.annotation.HostSideTestStaticInitializerKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.class
+  Compiled from "TinyFrameworkEnumComplex.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex>
+  minor version: 0
+  major version: 65
+  flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+  super_class: #x                        // java/lang/Enum
+  interfaces: 0, fields: 6, methods: 7, attributes: 3
+  public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex GREEN;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex BLUE;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private final java.lang.String mLongName;
+    descriptor: Ljava/lang/String;
+    flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private final java.lang.String mShortName;
+    descriptor: Ljava/lang/String;
+    flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $VALUES;
+    descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+
+  public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] values();
+    descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: getstatic     #x                 // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+         x: invokevirtual #x                 // Method "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;".clone:()Ljava/lang/Object;
+         x: checkcast     #x                 // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;"
+         x: areturn
+      LineNumberTable:
+
+  public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex valueOf(java.lang.String);
+    descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+         x: aload_0
+         x: invokestatic  #x                 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+         x: checkcast     #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  name   Ljava/lang/String;
+    MethodParameters:
+      Name                           Flags
+      <no name>                      mandated
+
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
+    descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=3, locals=5, args_size=5
+         x: aload_0
+         x: aload_1
+         x: iload_2
+         x: invokespecial #x                 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
+         x: aload_0
+         x: aload_3
+         x: putfield      #x                 // Field mLongName:Ljava/lang/String;
+        x: aload_0
+        x: aload         4
+        x: putfield      #x                 // Field mShortName:Ljava/lang/String;
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      18     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+            0      18     3 longName   Ljava/lang/String;
+            0      18     4 shortName   Ljava/lang/String;
+    MethodParameters:
+      Name                           Flags
+      <no name>                      synthetic
+      <no name>                      synthetic
+      <no name>
+      <no name>
+    Signature: #x                          // (Ljava/lang/String;Ljava/lang/String;)V
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public java.lang.String getLongName();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: getfield      #x                 // Field mLongName:Ljava/lang/String;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public java.lang.String getShortName();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: getfield      #x                 // Field mShortName:Ljava/lang/String;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $values();
+    descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: iconst_3
+         x: anewarray     #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+         x: dup
+         x: iconst_0
+         x: getstatic     #x                  // Field RED:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+         x: aastore
+        x: dup
+        x: iconst_1
+        x: getstatic     #x                  // Field GREEN:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: aastore
+        x: dup
+        x: iconst_2
+        x: getstatic     #x                 // Field BLUE:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: aastore
+        x: areturn
+      LineNumberTable:
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=6, locals=0, args_size=0
+         x: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+         x: dup
+         x: ldc           #x                 // String RED
+         x: iconst_0
+         x: ldc           #x                 // String Red
+         x: ldc           #x                 // String R
+        x: invokespecial #x                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+        x: putstatic     #x                  // Field RED:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+        x: dup
+        x: ldc           #x                 // String GREEN
+        x: iconst_1
+        x: ldc           #x                 // String Green
+        x: ldc           #x                 // String G
+        x: invokespecial #x                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+        x: putstatic     #x                  // Field GREEN:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+        x: dup
+        x: ldc           #x                 // String BLUE
+        x: iconst_2
+        x: ldc           #x                 // String Blue
+        x: ldc           #x                 // String B
+        x: invokespecial #x                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+        x: putstatic     #x                 // Field BLUE:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: invokestatic  #x                 // Method $values:()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: putstatic     #x                 // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: return
+      LineNumberTable:
+}
+Signature: #x                          // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;>;
+SourceFile: "TinyFrameworkEnumComplex.java"
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.class
+  Compiled from "TinyFrameworkEnumSimple.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple>
+  minor version: 0
+  major version: 65
+  flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+  super_class: #x                        // java/lang/Enum
+  interfaces: 0, fields: 3, methods: 5, attributes: 3
+  public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple DOG;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $VALUES;
+    descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+
+  public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] values();
+    descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: getstatic     #x                 // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+         x: invokevirtual #x                 // Method "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;".clone:()Ljava/lang/Object;
+         x: checkcast     #x                 // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;"
+         x: areturn
+      LineNumberTable:
+
+  public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple valueOf(java.lang.String);
+    descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+         x: aload_0
+         x: invokestatic  #x                 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+         x: checkcast     #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  name   Ljava/lang/String;
+    MethodParameters:
+      Name                           Flags
+      <no name>                      mandated
+
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
+    descriptor: (Ljava/lang/String;I)V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=3, locals=3, args_size=3
+         x: aload_0
+         x: aload_1
+         x: iload_2
+         x: invokespecial #x                 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       7     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    MethodParameters:
+      Name                           Flags
+      <no name>                      synthetic
+      <no name>                      synthetic
+    Signature: #x                          // ()V
+
+  private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
+    descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: iconst_2
+         x: anewarray     #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+         x: dup
+         x: iconst_0
+         x: getstatic     #x                  // Field CAT:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+         x: aastore
+        x: dup
+        x: iconst_1
+        x: getstatic     #x                  // Field DOG:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+        x: aastore
+        x: areturn
+      LineNumberTable:
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+         x: dup
+         x: ldc           #x                 // String CAT
+         x: iconst_0
+         x: invokespecial #x                 // Method "<init>":(Ljava/lang/String;I)V
+        x: putstatic     #x                  // Field CAT:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+        x: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+        x: dup
+        x: ldc           #x                 // String DOG
+        x: iconst_1
+        x: invokespecial #x                 // Method "<init>":(Ljava/lang/String;I)V
+        x: putstatic     #x                  // Field DOG:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+        x: invokestatic  #x                 // Method $values:()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+        x: putstatic     #x                 // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+        x: return
+      LineNumberTable:
+}
+Signature: #x                          // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;>;
+SourceFile: "TinyFrameworkEnumSimple.java"
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
+  Compiled from "TinyFrameworkExceptionTester.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 2
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester;
+
+  public static int testException();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=0
+         x: new           #x                  // class java/lang/IllegalStateException
+         x: dup
+         x: ldc           #x                  // String Inner exception
+         x: invokespecial #x                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
+         x: athrow
+        x: astore_0
+        x: new           #x                 // class java/lang/RuntimeException
+        x: dup
+        x: ldc           #x                 // String Outer exception
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V
+        x: athrow
+      Exception table:
+         from    to  target type
+             0    10    10   Class java/lang/Exception
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      11     0     e   Ljava/lang/Exception;
+      StackMapTable: number_of_entries = 1
+        frame_type = 74 /* same_locals_1_stack_item */
+          stack = [ class java/lang/Exception ]
+}
+SourceFile: "TinyFrameworkExceptionTester.java"
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.class
+  Compiled from "TinyFrameworkForTextPolicy.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 17, attributes: 1
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public int remove;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: iconst_1
+         x: putfield      #x                  // Field stub:I
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: iload_1
+         x: iconst_1
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0       4     1 value   I
+
+  public void toBeRemoved(java.lang.String);
+    descriptor: (Ljava/lang/String;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0       8     1   foo   Ljava/lang/String;
+
+  public java.lang.String toBeIgnoredObj();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+  public void toBeIgnoredV();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+  public boolean toBeIgnoredZ();
+    descriptor: ()Z
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+  public byte toBeIgnoredB();
+    descriptor: ()B
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+  public char toBeIgnoredC();
+    descriptor: ()C
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+  public short toBeIgnoredS();
+    descriptor: ()S
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+  public int toBeIgnoredI();
+    descriptor: ()I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+  public float toBeIgnoredF();
+    descriptor: ()F
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+  public double toBeIgnoredD();
+    descriptor: ()D
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String not supported on host side
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0      10     1 value   I
+
+  public int addTwo_host(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: iload_1
+         x: iconst_2
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0       4     1 value   I
+
+  public static native int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+
+  public static int addThree_host(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: iload_0
+         x: iconst_3
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0 value   I
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: ldc           #x                 // String This value shouldn\'t be seen on the host side.
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       3     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+}
+SourceFile: "TinyFrameworkForTextPolicy.java"
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.class
+  Compiled from "TinyFrameworkLambdas.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nested
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 8, attributes: 5
+  public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nested();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: invokedynamic #x,  0              // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+        x: putfield      #x                 // Field mSupplier:Ljava/util/function/Supplier;
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      14     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public java.util.function.Supplier<java.lang.Integer> getSupplier();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested;
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+         x: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static java.lang.Integer lambda$getSupplier_static$3();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: bipush        8
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+
+  private static java.lang.Integer lambda$getSupplier$2();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: bipush        7
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+
+  private static java.lang.Integer lambda$static$1();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: bipush        6
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+
+  private static java.lang.Integer lambda$new$0();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: iconst_5
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+         x: putstatic     #x                 // Field sSupplier:Ljava/util/function/Supplier;
+         x: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkLambdas.java"
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+  x: #x()
+    android.hosttest.annotation.HostSideTestStaticInitializerKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+BootstrapMethods:
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$new$0:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$getSupplier$2:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$getSupplier_static$3:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$static$1:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+InnerClasses:
+  public static #x= #x of #x;          // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+  public static final #x= #x of #x;    // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.class
+  Compiled from "TinyFrameworkLambdas.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 8, attributes: 5
+  public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: invokedynamic #x,  0              // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+        x: putfield      #x                 // Field mSupplier:Ljava/util/function/Supplier;
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      14     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public java.util.function.Supplier<java.lang.Integer> getSupplier();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas;
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+         x: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static java.lang.Integer lambda$getSupplier_static$3();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: iconst_4
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+
+  private static java.lang.Integer lambda$getSupplier$2();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: iconst_3
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+
+  private static java.lang.Integer lambda$static$1();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: iconst_2
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+
+  private static java.lang.Integer lambda$new$0();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: iconst_1
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+         x: putstatic     #x                 // Field sSupplier:Ljava/util/function/Supplier;
+         x: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkLambdas.java"
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+  x: #x()
+    android.hosttest.annotation.HostSideTestStaticInitializerKeep
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+BootstrapMethods:
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$new$0:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$getSupplier$2:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$getSupplier_static$3:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$static$1:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+InnerClasses:
+  public static #x= #x of #x;          // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+  public static final #x= #x of #x;    // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class
+  Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 3, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo;
+
+  public static void startThread(java.lang.Thread);
+    descriptor: (Ljava/lang/Thread;)V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: aload_0
+         x: iconst_1
+         x: invokevirtual #x                  // Method java/lang/Thread.setDaemon:(Z)V
+         x: aload_0
+         x: invokevirtual #x                 // Method java/lang/Thread.start:()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0 thread   Ljava/lang/Thread;
+
+  public static int add(int, int);
+    descriptor: (II)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: iload_0
+         x: iload_1
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0     a   I
+            0       4     1     b   I
+}
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+InnerClasses:
+  public static #x= #x of #x;          // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.class
+  Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 5, attributes: 5
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace;
+
+  public static boolean nonStaticMethodCallReplaceTester() throws java.lang.Exception;
+    descriptor: ()Z
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=2, args_size=0
+         x: new           #x                  // class java/util/concurrent/atomic/AtomicBoolean
+         x: dup
+         x: iconst_0
+         x: invokespecial #x                  // Method java/util/concurrent/atomic/AtomicBoolean."<init>":(Z)V
+         x: astore_0
+         x: new           #x                 // class java/lang/Thread
+        x: dup
+        x: aload_0
+        x: invokedynamic #x,  0             // InvokeDynamic #x:run:(Ljava/util/concurrent/atomic/AtomicBoolean;)Ljava/lang/Runnable;
+        x: invokespecial #x                 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
+        x: astore_1
+        x: aload_1
+        x: invokevirtual #x                 // Method java/lang/Thread.start:()V
+        x: aload_1
+        x: invokevirtual #x                 // Method java/lang/Thread.join:()V
+        x: aload_0
+        x: invokevirtual #x                 // Method java/util/concurrent/atomic/AtomicBoolean.get:()Z
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            9      27     0    ab   Ljava/util/concurrent/atomic/AtomicBoolean;
+           23      13     1    th   Ljava/lang/Thread;
+    Exceptions:
+      throws java.lang.Exception
+
+  public static int staticMethodCallReplaceTester();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: iconst_1
+         x: iconst_2
+         x: invokestatic  #x                 // Method originalAdd:(II)I
+         x: ireturn
+      LineNumberTable:
+
+  private static int originalAdd(int, int);
+    descriptor: (II)I
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: iload_0
+         x: iload_1
+         x: iadd
+         x: iconst_1
+         x: isub
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0     a   I
+            0       6     1     b   I
+
+  private static void lambda$nonStaticMethodCallReplaceTester$0(java.util.concurrent.atomic.AtomicBoolean);
+    descriptor: (Ljava/util/concurrent/atomic/AtomicBoolean;)V
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: aload_0
+         x: invokestatic  #x                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
+         x: invokevirtual #x                 // Method java/lang/Thread.isDaemon:()Z
+         x: invokevirtual #x                 // Method java/util/concurrent/atomic/AtomicBoolean.set:(Z)V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0    ab   Ljava/util/concurrent/atomic/AtomicBoolean;
+}
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+BootstrapMethods:
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()V
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.lambda$nonStaticMethodCallReplaceTester$0:(Ljava/util/concurrent/atomic/AtomicBoolean;)V
+      #x ()V
+InnerClasses:
+  public static #x= #x of #x;          // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+  public static final #x= #x of #x;    // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
+  Compiled from "TinyFrameworkNative.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 14, attributes: 2
+  int value;
+    descriptor: I
+    flags: (0x0000)
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+
+  public static native int nativeAddTwo(int);
+    descriptor: (I)I
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRedirect
+
+  public static int nativeAddTwo_should_be_like_this(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: iload_0
+         x: invokestatic  #x                  // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0   arg   I
+
+  public static native long nativeLongPlus(long, long);
+    descriptor: (JJ)J
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRedirect
+
+  public static long nativeLongPlus_should_be_like_this(long, long);
+    descriptor: (JJ)J
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=4, args_size=2
+         x: lload_0
+         x: lload_2
+         x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+         x: lreturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  arg1   J
+            0       6     2  arg2   J
+
+  public void setValue(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: aload_0
+         x: iload_1
+         x: putfield      #x                 // Field value:I
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+            0       6     1     v   I
+
+  public native int nativeNonStaticAddToValue(int);
+    descriptor: (I)I
+    flags: (0x0101) ACC_PUBLIC, ACC_NATIVE
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRedirect
+
+  public int nativeNonStaticAddToValue_should_be_like_this(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: aload_0
+         x: iload_1
+         x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeNonStaticAddToValue:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+            0       6     1   arg   I
+
+  public static native void nativeStillNotSupported();
+    descriptor: ()V
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestThrow
+
+  public static native void nativeStillKeep();
+    descriptor: ()V
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+
+  public static void nativeStillNotSupported_should_be_like_this();
+    descriptor: ()V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         x: athrow
+      LineNumberTable:
+
+  public static native byte nativeBytePlus(byte, byte);
+    descriptor: (BB)B
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRedirect
+
+  public void notNativeRedirected();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRedirect
+
+  public static void notNativeStaticRedirected();
+    descriptor: ()V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         x: athrow
+      LineNumberTable:
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRedirect
+}
+SourceFile: "TinyFrameworkNative.java"
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+  x: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestRedirectionClass(
+      value="TinyFrameworkNative_host"
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.class
+  Compiled from "TinyFrameworkNative_host.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 7, attributes: 2
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host;
+
+  public static int nativeAddTwo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: iload_0
+         x: iconst_2
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0   arg   I
+
+  public static long nativeLongPlus(long, long);
+    descriptor: (JJ)J
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=4, args_size=2
+         x: lload_0
+         x: lload_2
+         x: ladd
+         x: lreturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  arg1   J
+            0       4     2  arg2   J
+
+  public static int nativeNonStaticAddToValue(com.android.hoststubgen.test.tinyframework.TinyFrameworkNative, int);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: aload_0
+         x: getfield      #x                  // Field com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.value:I
+         x: iload_1
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       7     0 source   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+            0       7     1   arg   I
+
+  public static byte nativeBytePlus(byte, byte);
+    descriptor: (BB)B
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: iload_0
+         x: iload_1
+         x: iadd
+         x: i2b
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  arg1   B
+            0       5     1  arg2   B
+
+  public static void notNativeRedirected(com.android.hoststubgen.test.tinyframework.TinyFrameworkNative);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;)V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=0, locals=1, args_size=1
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       1     0 source   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+
+  public static void notNativeStaticRedirected();
+    descriptor: ()V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=0, locals=0, args_size=0
+         x: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkNative_host.java"
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 65
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 3, attributes: 5
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=2, args_size=2
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+            0       5     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: iconst_1
+         x: invokestatic  #x                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+}
+Signature: #x                          // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x                 // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 65
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 3, attributes: 5
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: iconst_2
+         x: invokestatic  #x                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+}
+Signature: #x                          // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x                 // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 65
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 3, attributes: 5
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=2, args_size=2
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+            0       5     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: iconst_3
+         x: invokestatic  #x                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+}
+Signature: #x                          // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 65
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 3, attributes: 5
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: iconst_4
+         x: invokestatic  #x                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+}
+Signature: #x                          // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier_static
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 1, attributes: 3
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: iload_1
+         x: putfield      #x                  // Field value:I
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass;
+            0      10     1     x   I
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  public static #x= #x of #x;           // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 1, attributes: 3
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: iconst_5
+         x: putfield      #x                  // Field value:I
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass;
+            0      10     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  public #x= #x of #x;                  // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 65
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 3, attributes: 5
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: bipush        7
+         x: invokestatic  #x                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+}
+Signature: #x                          // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass.getSupplier_static
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  public static #x= #x of #x;          // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 1, attributes: 3
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: bipush        8
+         x: putfield      #x                  // Field value:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass;
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  public static #x= #x of #x;          // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 3
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: bipush        6
+         x: putfield      #x                  // Field value:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass;
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+         x: dup
+         x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1."<init>":()V
+         x: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  public static #x= #x of #x;           // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+  public static #x= #x of #x;           // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass extends com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  interfaces: 0, fields: 0, methods: 1, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: aload_0
+         x: iload_1
+         x: invokespecial #x                  // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass."<init>":(I)V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass;
+            0       6     1     x   I
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  public static #x= #x of #x;           // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 4, attributes: 4
+  public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+         x: dup
+         x: aload_0
+        x: invokespecial #x                  // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+        x: putfield      #x                 // Field mSupplier:Ljava/util/function/Supplier;
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      17     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+
+  public java.util.function.Supplier<java.lang.Integer> getSupplier();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+         x: dup
+         x: aload_0
+         x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       9     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+         x: dup
+         x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4."<init>":()V
+         x: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+         x: dup
+         x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2."<init>":()V
+         x: putstatic     #x                 // Field sSupplier:Ljava/util/function/Supplier;
+        x: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  public static #x= #x of #x;          // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;          // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;          // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public #x= #x of #x;                 // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;          // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.class
+  Compiled from "TinyFrameworkPackageRedirect.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 2
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect;
+
+  public static int foo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                  // class com/unsupported/UnsupportedClass
+         x: dup
+         x: iload_0
+         x: invokespecial #x                  // Method com/unsupported/UnsupportedClass."<init>":(I)V
+         x: invokevirtual #x                 // Method com/unsupported/UnsupportedClass.getValue:()I
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      12     0 value   I
+}
+SourceFile: "TinyFrameworkPackageRedirect.java"
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.class
+  Compiled from "TinyFrameworkRenamedClassCaller.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 2
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller;
+
+  public static int foo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
+         x: dup
+         x: iload_0
+         x: invokespecial #x                  // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed."<init>":(I)V
+         x: invokevirtual #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getValue:()I
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      12     0 value   I
+}
+SourceFile: "TinyFrameworkRenamedClassCaller.java"
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.class
+  Compiled from "TinyFrameworkToBeRenamed.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 2
+  private final int mValue;
+    descriptor: I
+    flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: iload_1
+         x: putfield      #x                  // Field mValue:I
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed;
+            0      10     1 value   I
+
+  public int getValue();
+    descriptor: ()I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: getfield      #x                  // Field mValue:I
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed;
+}
+SourceFile: "TinyFrameworkToBeRenamed.java"
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/packagetest/A.class
+  Compiled from "A.java"
+public class com.android.hoststubgen.test.tinyframework.packagetest.A
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/packagetest/A
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.packagetest.A();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/packagetest/A;
+}
+SourceFile: "A.java"
+## Class: com/android/hoststubgen/test/tinyframework/packagetest/B.class
+  Compiled from "B.java"
+public class com.android.hoststubgen.test.tinyframework.packagetest.B
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/packagetest/B
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.packagetest.B();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/packagetest/B;
+}
+SourceFile: "B.java"
+## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/A.class
+  Compiled from "A.java"
+public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/packagetest/sub/A
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.packagetest.sub.A();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/packagetest/sub/A;
+}
+SourceFile: "A.java"
+## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/B.class
+  Compiled from "B.java"
+public class com.android.hoststubgen.test.tinyframework.packagetest.sub.B
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/packagetest/sub/B
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.packagetest.sub.B();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/packagetest/sub/B;
+}
+SourceFile: "B.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C1.class
+  Compiled from "C1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.C1
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/C1
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.C1();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/C1;
+}
+SourceFile: "C1.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C2.class
+  Compiled from "C2.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.C2 extends com.android.hoststubgen.test.tinyframework.subclasstest.C1
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/C2
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/subclasstest/C1
+  interfaces: 0, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.C2();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method com/android/hoststubgen/test/tinyframework/subclasstest/C1."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/C2;
+}
+SourceFile: "C2.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C3.class
+  Compiled from "C3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.C3 extends com.android.hoststubgen.test.tinyframework.subclasstest.C2
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/C3
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/subclasstest/C2
+  interfaces: 0, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.C3();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method com/android/hoststubgen/test/tinyframework/subclasstest/C2."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/C3;
+}
+SourceFile: "C3.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/CA.class
+  Compiled from "CA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.CA
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/CA
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.CA();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/CA;
+}
+SourceFile: "CA.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/CB.class
+  Compiled from "CB.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.CB
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/CB
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.CB();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/CB;
+}
+SourceFile: "CB.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1.class
+  Compiled from "Class_C1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C1 extends com.android.hoststubgen.test.tinyframework.subclasstest.C1
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/subclasstest/C1
+  interfaces: 0, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.Class_C1();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method com/android/hoststubgen/test/tinyframework/subclasstest/C1."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_C1;
+}
+SourceFile: "Class_C1.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2.class
+  Compiled from "Class_C2.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C2 extends com.android.hoststubgen.test.tinyframework.subclasstest.C2
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/subclasstest/C2
+  interfaces: 0, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.Class_C2();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method com/android/hoststubgen/test/tinyframework/subclasstest/C2."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_C2;
+}
+SourceFile: "Class_C2.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3.class
+  Compiled from "Class_C3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C3 extends com.android.hoststubgen.test.tinyframework.subclasstest.C3
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/subclasstest/C3
+  interfaces: 0, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.Class_C3();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method com/android/hoststubgen/test/tinyframework/subclasstest/C3."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_C3;
+}
+SourceFile: "Class_C3.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_CA.class
+  Compiled from "Class_CA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_CA extends com.android.hoststubgen.test.tinyframework.subclasstest.CA
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_CA
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/subclasstest/CA
+  interfaces: 0, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.Class_CA();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method com/android/hoststubgen/test/tinyframework/subclasstest/CA."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_CA;
+}
+SourceFile: "Class_CA.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB.class
+  Compiled from "Class_CB.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_CB extends com.android.hoststubgen.test.tinyframework.subclasstest.CB
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/subclasstest/CB
+  interfaces: 0, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.Class_CB();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method com/android/hoststubgen/test/tinyframework/subclasstest/CB."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_CB;
+}
+SourceFile: "Class_CB.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB_IA.class
+  Compiled from "Class_CB_IA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_CB_IA extends com.android.hoststubgen.test.tinyframework.subclasstest.CB implements com.android.hoststubgen.test.tinyframework.subclasstest.IA
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB_IA
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/subclasstest/CB
+  interfaces: 1, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.Class_CB_IA();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method com/android/hoststubgen/test/tinyframework/subclasstest/CB."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_CB_IA;
+}
+SourceFile: "Class_CB_IA.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1.class
+  Compiled from "Class_I1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1 implements com.android.hoststubgen.test.tinyframework.subclasstest.I1
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_I1;
+}
+SourceFile: "Class_I1.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA.class
+  Compiled from "Class_I1_IA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1_IA implements com.android.hoststubgen.test.tinyframework.subclasstest.I1,com.android.hoststubgen.test.tinyframework.subclasstest.IA
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA
+  super_class: #x                         // java/lang/Object
+  interfaces: 2, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1_IA();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA;
+}
+SourceFile: "Class_I1_IA.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2.class
+  Compiled from "Class_I2.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I2 implements com.android.hoststubgen.test.tinyframework.subclasstest.I2
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I2();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_I2;
+}
+SourceFile: "Class_I2.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3.class
+  Compiled from "Class_I3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3 implements com.android.hoststubgen.test.tinyframework.subclasstest.I3
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_I3;
+}
+SourceFile: "Class_I3.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3_IA.class
+  Compiled from "Class_I3_IA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3_IA implements com.android.hoststubgen.test.tinyframework.subclasstest.I3,com.android.hoststubgen.test.tinyframework.subclasstest.IA
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3_IA
+  super_class: #x                         // java/lang/Object
+  interfaces: 2, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3_IA();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_I3_IA;
+}
+SourceFile: "Class_I3_IA.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA.class
+  Compiled from "Class_IA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA implements com.android.hoststubgen.test.tinyframework.subclasstest.IA
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_IA;
+}
+SourceFile: "Class_IA.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I1.class
+  Compiled from "Class_IA_I1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA_I1 implements com.android.hoststubgen.test.tinyframework.subclasstest.IA,com.android.hoststubgen.test.tinyframework.subclasstest.I1
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I1
+  super_class: #x                         // java/lang/Object
+  interfaces: 2, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA_I1();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I1;
+}
+SourceFile: "Class_IA_I1.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I3.class
+  Compiled from "Class_IA_I3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA_I3 implements com.android.hoststubgen.test.tinyframework.subclasstest.IA,com.android.hoststubgen.test.tinyframework.subclasstest.I3
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I3
+  super_class: #x                         // java/lang/Object
+  interfaces: 2, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA_I3();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I3;
+}
+SourceFile: "Class_IA_I3.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB.class
+  Compiled from "Class_IB.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IB implements com.android.hoststubgen.test.tinyframework.subclasstest.IB
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IB();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_IB;
+}
+SourceFile: "Class_IB.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB_IA.class
+  Compiled from "Class_IB_IA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IB_IA implements com.android.hoststubgen.test.tinyframework.subclasstest.IB,com.android.hoststubgen.test.tinyframework.subclasstest.IA
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB_IA
+  super_class: #x                         // java/lang/Object
+  interfaces: 2, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IB_IA();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_IB_IA;
+}
+SourceFile: "Class_IB_IA.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_None.class
+  Compiled from "Class_None.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_None
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_None
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 1
+  public com.android.hoststubgen.test.tinyframework.subclasstest.Class_None();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/subclasstest/Class_None;
+}
+SourceFile: "Class_None.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I1.class
+  Compiled from "I1.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.I1
+  minor version: 0
+  major version: 65
+  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/I1
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 0, attributes: 1
+}
+SourceFile: "I1.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I2.class
+  Compiled from "I2.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.I2 extends com.android.hoststubgen.test.tinyframework.subclasstest.I1
+  minor version: 0
+  major version: 65
+  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/I2
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 1
+}
+SourceFile: "I2.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I3.class
+  Compiled from "I3.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.I3 extends com.android.hoststubgen.test.tinyframework.subclasstest.I2
+  minor version: 0
+  major version: 65
+  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/I3
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 1
+}
+SourceFile: "I3.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/IA.class
+  Compiled from "IA.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.IA
+  minor version: 0
+  major version: 65
+  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/IA
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 0, attributes: 1
+}
+SourceFile: "IA.java"
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/IB.class
+  Compiled from "IB.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.IB
+  minor version: 0
+  major version: 65
+  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/IB
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 0, attributes: 1
+}
+SourceFile: "IB.java"
+## Class: com/supported/UnsupportedClass.class
+  Compiled from "UnsupportedClass.java"
+public class com.supported.UnsupportedClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/supported/UnsupportedClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 2
+  private final int mValue;
+    descriptor: I
+    flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+
+  public com.supported.UnsupportedClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: iload_1
+         x: putfield      #x                  // Field mValue:I
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/supported/UnsupportedClass;
+            0      10     1 value   I
+
+  public int getValue();
+    descriptor: ()I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: getfield      #x                  // Field mValue:I
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/supported/UnsupportedClass;
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/unsupported/UnsupportedClass.class
+  Compiled from "UnsupportedClass.java"
+public class com.unsupported.UnsupportedClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                         // com/unsupported/UnsupportedClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 2
+  public com.unsupported.UnsupportedClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: new           #x                  // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                  // String This class is not supported
+        x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      14     0  this   Lcom/unsupported/UnsupportedClass;
+            0      14     1 value   I
+
+  public int getValue();
+    descriptor: ()I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                  // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                  // String This class is not supported
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/unsupported/UnsupportedClass;
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/03-hoststubgen-test-tiny-framework-host-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/03-hoststubgen-test-tiny-framework-host-dump.txt
new file mode 100644
index 0000000..84a8373
--- /dev/null
+++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/03-hoststubgen-test-tiny-framework-host-dump.txt
@@ -0,0 +1,3727 @@
+## Class: android/hosttest/annotation/HostSideTestClassLoadHook.class
+  Compiled from "HostSideTestClassLoadHook.java"
+public interface android.hosttest.annotation.HostSideTestClassLoadHook extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestClassLoadHook
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  public abstract java.lang.String value();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "HostSideTestClassLoadHook.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestKeep.class
+  Compiled from "HostSideTestKeep.java"
+public interface android.hosttest.annotation.HostSideTestKeep extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestKeep
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestKeep.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+  x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestRedirect.class
+  Compiled from "HostSideTestRedirect.java"
+public interface android.hosttest.annotation.HostSideTestRedirect extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestRedirect
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestRedirect.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestRedirectionClass.class
+  Compiled from "HostSideTestRedirectionClass.java"
+public interface android.hosttest.annotation.HostSideTestRedirectionClass extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestRedirectionClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  public abstract java.lang.String value();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "HostSideTestRedirectionClass.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestRemove.class
+  Compiled from "HostSideTestRemove.java"
+public interface android.hosttest.annotation.HostSideTestRemove extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestRemove
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestRemove.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+  x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestStaticInitializerKeep.class
+  Compiled from "HostSideTestStaticInitializerKeep.java"
+public interface android.hosttest.annotation.HostSideTestStaticInitializerKeep extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestStaticInitializerKeep
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestStaticInitializerKeep.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+  x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestSubstitute.class
+  Compiled from "HostSideTestSubstitute.java"
+public interface android.hosttest.annotation.HostSideTestSubstitute extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestSubstitute
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  public abstract java.lang.String suffix();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "HostSideTestSubstitute.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestThrow.class
+  Compiled from "HostSideTestThrow.java"
+public interface android.hosttest.annotation.HostSideTestThrow extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestThrow
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestThrow.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+  x: #x(#x=[e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestWholeClassKeep.class
+  Compiled from "HostSideTestWholeClassKeep.java"
+public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestWholeClassKeep
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestWholeClassKeep.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy.class
+  Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 4
+  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: iload_0
+         x: iconst_2
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0     a   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;           // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub.class
+  Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 4
+  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int addOne(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: iload_0
+         x: iconst_1
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0     a   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;             // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl.class
+  Compiled from "IPretendingAidl.java"
+public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl
+  minor version: 0
+  major version: 65
+  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 0, attributes: 4
+}
+InnerClasses:
+  public static #x= #x of #x;            // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class
+  Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R$Nested
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/R$Nested
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 4
+  public static int[] ARRAY;
+    descriptor: [I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public com.android.hoststubgen.test.tinyframework.R$Nested();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/R$Nested;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: iconst_1
+         x: newarray       int
+         x: dup
+         x: iconst_0
+         x: iconst_1
+         x: iastore
+         x: putstatic     #x                 // Field ARRAY:[I
+        x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;             // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/R.class
+  Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/R
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 4
+  public com.android.hoststubgen.test.tinyframework.R();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/R;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;             // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/R$Nested
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.class
+  Compiled from "TinyFrameworkAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 7, attributes: 3
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+         x: ldc           #x                  // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: iconst_1
+         x: putfield      #x                 // Field keep:I
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: iload_1
+         x: iconst_1
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+            0       4     1 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: iload_1
+         x: iconst_2
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+            0       4     1 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: iload_0
+         x: iconst_3
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Unreachable
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        x: athrow
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestThrow
+
+  public int toBeIgnored();
+    descriptor: ()I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: iconst_0
+         x: ireturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestIgnore
+}
+SourceFile: "TinyFrameworkAnnotations.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+  x: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
+  Compiled from "TinyFrameworkClassLoadHook.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 3, attributes: 3
+  public static final java.util.Set<java.lang.Class<?>> sLoadedClasses;
+    descriptor: Ljava/util/Set;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/Set<Ljava/lang/Class<*>;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook();
+    descriptor: ()V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static void onClassLoaded(java.lang.Class<?>);
+    descriptor: (Ljava/lang/Class;)V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: getstatic     #x                 // Field sLoadedClasses:Ljava/util/Set;
+         x: aload_0
+         x: invokeinterface #x,  2           // InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z
+         x: pop
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0 clazz   Ljava/lang/Class;
+      LocalVariableTypeTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0 clazz   Ljava/lang/Class<*>;
+    Signature: #x                          // (Ljava/lang/Class<*>;)V
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: new           #x                 // class java/util/HashSet
+         x: dup
+         x: invokespecial #x                 // Method java/util/HashSet."<init>":()V
+         x: putstatic     #x                 // Field sLoadedClasses:Ljava/util/Set;
+        x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkClassLoadHook.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations.class
+  Compiled from "TinyFrameworkClassWideAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 4, attributes: 3
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: iconst_1
+         x: putfield      #x                 // Field keep:I
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: iload_1
+         x: iconst_1
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+            0       4     1 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: iload_1
+         x: iconst_2
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+            0       4     1 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Unreachable
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        x: athrow
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestThrow
+}
+SourceFile: "TinyFrameworkClassWideAnnotations.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.class
+  Compiled from "TinyFrameworkClassWithInitializerDefault.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 0, attributes: 3
+  public static boolean sInitialized;
+    descriptor: Z
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static java.lang.Object sObject;
+    descriptor: Ljava/lang/Object;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+}
+SourceFile: "TinyFrameworkClassWithInitializerDefault.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub.class
+  Compiled from "TinyFrameworkClassWithInitializerStub.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerStub
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 1, attributes: 3
+  public static boolean sInitialized;
+    descriptor: Z
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static java.lang.Object sObject;
+    descriptor: Ljava/lang/Object;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+         x: ldc           #x                 // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: iconst_1
+         x: putstatic     #x                 // Field sInitialized:Z
+        x: new           #x                  // class java/lang/Object
+        x: dup
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: putstatic     #x                 // Field sObject:Ljava/lang/Object;
+        x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkClassWithInitializerStub.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+  x: #x()
+    android.hosttest.annotation.HostSideTestStaticInitializerKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.class
+  Compiled from "TinyFrameworkEnumComplex.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex>
+  minor version: 0
+  major version: 65
+  flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+  super_class: #x                         // java/lang/Enum
+  interfaces: 0, fields: 6, methods: 7, attributes: 4
+  public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex GREEN;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex BLUE;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private final java.lang.String mLongName;
+    descriptor: Ljava/lang/String;
+    flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private final java.lang.String mShortName;
+    descriptor: Ljava/lang/String;
+    flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $VALUES;
+    descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] values();
+    descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: getstatic     #x                 // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+         x: invokevirtual #x                 // Method "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;".clone:()Ljava/lang/Object;
+         x: checkcast     #x                 // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;"
+         x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex valueOf(java.lang.String);
+    descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+         x: aload_0
+         x: invokestatic  #x                 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+         x: checkcast     #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  name   Ljava/lang/String;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    MethodParameters:
+      Name                           Flags
+      <no name>                      mandated
+
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
+    descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=3, locals=5, args_size=5
+         x: aload_0
+         x: aload_1
+         x: iload_2
+         x: invokespecial #x                 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
+         x: aload_0
+         x: aload_3
+         x: putfield      #x                 // Field mLongName:Ljava/lang/String;
+        x: aload_0
+        x: aload         4
+        x: putfield      #x                 // Field mShortName:Ljava/lang/String;
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      18     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+            0      18     3 longName   Ljava/lang/String;
+            0      18     4 shortName   Ljava/lang/String;
+    Signature: #x                          // (Ljava/lang/String;Ljava/lang/String;)V
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+    MethodParameters:
+      Name                           Flags
+      <no name>                      synthetic
+      <no name>                      synthetic
+      <no name>
+      <no name>
+
+  public java.lang.String getLongName();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: getfield      #x                 // Field mLongName:Ljava/lang/String;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public java.lang.String getShortName();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: getfield      #x                 // Field mShortName:Ljava/lang/String;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $values();
+    descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: iconst_3
+         x: anewarray     #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+         x: dup
+         x: iconst_0
+         x: getstatic     #x                 // Field RED:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+         x: aastore
+        x: dup
+        x: iconst_1
+        x: getstatic     #x                 // Field GREEN:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: aastore
+        x: dup
+        x: iconst_2
+        x: getstatic     #x                 // Field BLUE:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: aastore
+        x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=6, locals=0, args_size=0
+         x: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+         x: dup
+         x: ldc           #x                 // String RED
+         x: iconst_0
+         x: ldc           #x                 // String Red
+         x: ldc           #x                 // String R
+        x: invokespecial #x                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+        x: putstatic     #x                 // Field RED:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+        x: dup
+        x: ldc           #x                 // String GREEN
+        x: iconst_1
+        x: ldc           #x                 // String Green
+        x: ldc           #x                 // String G
+        x: invokespecial #x                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+        x: putstatic     #x                 // Field GREEN:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+        x: dup
+        x: ldc           #x                 // String BLUE
+        x: iconst_2
+        x: ldc           #x                 // String Blue
+        x: ldc           #x                 // String B
+        x: invokespecial #x                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+        x: putstatic     #x                 // Field BLUE:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: invokestatic  #x                 // Method $values:()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: putstatic     #x                 // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+Signature: #x                           // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;>;
+SourceFile: "TinyFrameworkEnumComplex.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.class
+  Compiled from "TinyFrameworkEnumSimple.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple>
+  minor version: 0
+  major version: 65
+  flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+  super_class: #x                         // java/lang/Enum
+  interfaces: 0, fields: 3, methods: 5, attributes: 4
+  public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple DOG;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $VALUES;
+    descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] values();
+    descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: getstatic     #x                 // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+         x: invokevirtual #x                 // Method "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;".clone:()Ljava/lang/Object;
+         x: checkcast     #x                 // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;"
+         x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple valueOf(java.lang.String);
+    descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+         x: aload_0
+         x: invokestatic  #x                 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+         x: checkcast     #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  name   Ljava/lang/String;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    MethodParameters:
+      Name                           Flags
+      <no name>                      mandated
+
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
+    descriptor: (Ljava/lang/String;I)V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=3, locals=3, args_size=3
+         x: aload_0
+         x: aload_1
+         x: iload_2
+         x: invokespecial #x                 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       7     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    Signature: #x                          // ()V
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    MethodParameters:
+      Name                           Flags
+      <no name>                      synthetic
+      <no name>                      synthetic
+
+  private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
+    descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: iconst_2
+         x: anewarray     #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+         x: dup
+         x: iconst_0
+         x: getstatic     #x                 // Field CAT:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+         x: aastore
+        x: dup
+        x: iconst_1
+        x: getstatic     #x                 // Field DOG:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+        x: aastore
+        x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+         x: dup
+         x: ldc           #x                 // String CAT
+         x: iconst_0
+         x: invokespecial #x                 // Method "<init>":(Ljava/lang/String;I)V
+        x: putstatic     #x                 // Field CAT:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+        x: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+        x: dup
+        x: ldc           #x                 // String DOG
+        x: iconst_1
+        x: invokespecial #x                 // Method "<init>":(Ljava/lang/String;I)V
+        x: putstatic     #x                 // Field DOG:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+        x: invokestatic  #x                 // Method $values:()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+        x: putstatic     #x                 // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+        x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+Signature: #x                           // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;>;
+SourceFile: "TinyFrameworkEnumSimple.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
+  Compiled from "TinyFrameworkExceptionTester.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int testException();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=0
+         x: new           #x                 // class java/lang/IllegalStateException
+         x: dup
+         x: ldc           #x                 // String Inner exception
+         x: invokespecial #x                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
+         x: athrow
+        x: astore_0
+        x: new           #x                 // class java/lang/RuntimeException
+        x: dup
+        x: ldc           #x                 // String Outer exception
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V
+        x: athrow
+      Exception table:
+         from    to  target type
+             0    10    10   Class java/lang/Exception
+      StackMapTable: number_of_entries = 1
+        frame_type = 74 /* same_locals_1_stack_item */
+          stack = [ class java/lang/Exception ]
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      11     0     e   Ljava/lang/Exception;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkExceptionTester.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.class
+  Compiled from "TinyFrameworkForTextPolicy.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 15, attributes: 2
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                  // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: iconst_1
+         x: putfield      #x                 // Field stub:I
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: iload_1
+         x: iconst_1
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0       4     1 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.String toBeIgnoredObj();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aconst_null
+         x: areturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public void toBeIgnoredV();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=0, locals=1, args_size=1
+         x: return
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public boolean toBeIgnoredZ();
+    descriptor: ()Z
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: iconst_0
+         x: ireturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public byte toBeIgnoredB();
+    descriptor: ()B
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: iconst_0
+         x: ireturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public char toBeIgnoredC();
+    descriptor: ()C
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: iconst_0
+         x: ireturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public short toBeIgnoredS();
+    descriptor: ()S
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: iconst_0
+         x: ireturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public int toBeIgnoredI();
+    descriptor: ()I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: iconst_0
+         x: ireturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public float toBeIgnoredF();
+    descriptor: ()F
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: fconst_0
+         x: freturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public double toBeIgnoredD();
+    descriptor: ()D
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: dconst_0
+         x: dreturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: iload_1
+         x: iconst_2
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0       4     1 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: iload_0
+         x: iconst_3
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Unreachable
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        x: athrow
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkForTextPolicy.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.class
+  Compiled from "TinyFrameworkLambdas.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nested
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 8, attributes: 6
+  public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nested();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+        x: putfield      #x                 // Field mSupplier:Ljava/util/function/Supplier;
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      14     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public java.util.function.Supplier<java.lang.Integer> getSupplier();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested;
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+         x: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static java.lang.Integer lambda$getSupplier_static$3();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: bipush        8
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static java.lang.Integer lambda$getSupplier$2();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: bipush        7
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static java.lang.Integer lambda$static$1();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: bipush        6
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static java.lang.Integer lambda$new$0();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: iconst_5
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+         x: putstatic     #x                 // Field sSupplier:Ljava/util/function/Supplier;
+         x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;            // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+  public static final #x= #x of #x;    // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+SourceFile: "TinyFrameworkLambdas.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+  x: #x()
+    android.hosttest.annotation.HostSideTestStaticInitializerKeep
+BootstrapMethods:
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$new$0:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$getSupplier$2:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$getSupplier_static$3:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$static$1:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.class
+  Compiled from "TinyFrameworkLambdas.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 8, attributes: 6
+  public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+        x: putfield      #x                 // Field mSupplier:Ljava/util/function/Supplier;
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      14     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public java.util.function.Supplier<java.lang.Integer> getSupplier();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas;
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+         x: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static java.lang.Integer lambda$getSupplier_static$3();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: iconst_4
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static java.lang.Integer lambda$getSupplier$2();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: iconst_3
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static java.lang.Integer lambda$static$1();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: iconst_2
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static java.lang.Integer lambda$new$0();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: iconst_1
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+         x: putstatic     #x                 // Field sSupplier:Ljava/util/function/Supplier;
+         x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;           // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+  public static final #x= #x of #x;    // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+SourceFile: "TinyFrameworkLambdas.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+  x: #x()
+    android.hosttest.annotation.HostSideTestStaticInitializerKeep
+BootstrapMethods:
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$new$0:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$getSupplier$2:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$getSupplier_static$3:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$static$1:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class
+  Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 3, attributes: 4
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static void startThread(java.lang.Thread);
+    descriptor: (Ljava/lang/Thread;)V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: aload_0
+         x: iconst_1
+         x: invokevirtual #x                 // Method java/lang/Thread.setDaemon:(Z)V
+         x: aload_0
+         x: invokevirtual #x                 // Method java/lang/Thread.start:()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0 thread   Ljava/lang/Thread;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int add(int, int);
+    descriptor: (II)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: iload_0
+         x: iload_1
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0     a   I
+            0       4     1     b   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;             // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.class
+  Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 4, attributes: 6
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static boolean nonStaticMethodCallReplaceTester() throws java.lang.Exception;
+    descriptor: ()Z
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=2, args_size=0
+         x: new           #x                 // class java/util/concurrent/atomic/AtomicBoolean
+         x: dup
+         x: iconst_0
+         x: invokespecial #x                 // Method java/util/concurrent/atomic/AtomicBoolean."<init>":(Z)V
+         x: astore_0
+         x: new           #x                 // class java/lang/Thread
+        x: dup
+        x: aload_0
+        x: invokedynamic #x,  0             // InvokeDynamic #x:run:(Ljava/util/concurrent/atomic/AtomicBoolean;)Ljava/lang/Runnable;
+        x: invokespecial #x                 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
+        x: astore_1
+        x: aload_1
+        x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.startThread:(Ljava/lang/Thread;)V
+        x: aload_1
+        x: invokevirtual #x                 // Method java/lang/Thread.join:()V
+        x: aload_0
+        x: invokevirtual #x                 // Method java/util/concurrent/atomic/AtomicBoolean.get:()Z
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            9      27     0    ab   Ljava/util/concurrent/atomic/AtomicBoolean;
+           23      13     1    th   Ljava/lang/Thread;
+    Exceptions:
+      throws java.lang.Exception
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int staticMethodCallReplaceTester();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: iconst_1
+         x: iconst_2
+         x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.add:(II)I
+         x: ireturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static void lambda$nonStaticMethodCallReplaceTester$0(java.util.concurrent.atomic.AtomicBoolean);
+    descriptor: (Ljava/util/concurrent/atomic/AtomicBoolean;)V
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: aload_0
+         x: invokestatic  #x                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
+         x: invokevirtual #x                 // Method java/lang/Thread.isDaemon:()Z
+         x: invokevirtual #x                 // Method java/util/concurrent/atomic/AtomicBoolean.set:(Z)V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0    ab   Ljava/util/concurrent/atomic/AtomicBoolean;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;            // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+  public static final #x= #x of #x;    // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+BootstrapMethods:
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()V
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.lambda$nonStaticMethodCallReplaceTester$0:(Ljava/util/concurrent/atomic/AtomicBoolean;)V
+      #x ()V
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
+  Compiled from "TinyFrameworkNative.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 14, attributes: 3
+  int value;
+    descriptor: I
+    flags: (0x0000)
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int nativeAddTwo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: iload_0
+         x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+         x: ireturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRedirect
+
+  public static int nativeAddTwo_should_be_like_this(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: iload_0
+         x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0   arg   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static long nativeLongPlus(long, long);
+    descriptor: (JJ)J
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=4, args_size=2
+         x: lload_0
+         x: lload_2
+         x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+         x: lreturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRedirect
+
+  public static long nativeLongPlus_should_be_like_this(long, long);
+    descriptor: (JJ)J
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=4, args_size=2
+         x: lload_0
+         x: lload_2
+         x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+         x: lreturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  arg1   J
+            0       6     2  arg2   J
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public void setValue(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: aload_0
+         x: iload_1
+         x: putfield      #x                 // Field value:I
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+            0       6     1     v   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public int nativeNonStaticAddToValue(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: aload_0
+         x: iload_1
+         x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeNonStaticAddToValue:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I
+         x: ireturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRedirect
+
+  public int nativeNonStaticAddToValue_should_be_like_this(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: aload_0
+         x: iload_1
+         x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeNonStaticAddToValue:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+            0       6     1   arg   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static void nativeStillNotSupported();
+    descriptor: ()V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Unreachable
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        x: athrow
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestThrow
+
+  public static native void nativeStillKeep();
+    descriptor: ()V
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static void nativeStillNotSupported_should_be_like_this();
+    descriptor: ()V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         x: athrow
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static byte nativeBytePlus(byte, byte);
+    descriptor: (BB)B
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: iload_0
+         x: iload_1
+         x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeBytePlus:(BB)B
+         x: ireturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRedirect
+
+  public void notNativeRedirected();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.notNativeRedirected:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;)V
+         x: return
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRedirect
+
+  public static void notNativeStaticRedirected();
+    descriptor: ()V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=0, locals=0, args_size=0
+         x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.notNativeStaticRedirected:()V
+         x: return
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRedirect
+}
+SourceFile: "TinyFrameworkNative.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+  x: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestRedirectionClass(
+      value="TinyFrameworkNative_host"
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.class
+  Compiled from "TinyFrameworkNative_host.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 7, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int nativeAddTwo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: iload_0
+         x: iconst_2
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0   arg   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static long nativeLongPlus(long, long);
+    descriptor: (JJ)J
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=4, args_size=2
+         x: lload_0
+         x: lload_2
+         x: ladd
+         x: lreturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  arg1   J
+            0       4     2  arg2   J
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int nativeNonStaticAddToValue(com.android.hoststubgen.test.tinyframework.TinyFrameworkNative, int);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: aload_0
+         x: getfield      #x                 // Field com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.value:I
+         x: iload_1
+         x: iadd
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       7     0 source   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+            0       7     1   arg   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static byte nativeBytePlus(byte, byte);
+    descriptor: (BB)B
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: iload_0
+         x: iload_1
+         x: iadd
+         x: i2b
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  arg1   B
+            0       5     1  arg2   B
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static void notNativeRedirected(com.android.hoststubgen.test.tinyframework.TinyFrameworkNative);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;)V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=0, locals=1, args_size=1
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       1     0 source   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static void notNativeStaticRedirected();
+    descriptor: ()V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=0, locals=0, args_size=0
+         x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkNative_host.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 65
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 3, attributes: 6
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=2, args_size=2
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+            0       5     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: iconst_1
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+EnclosingMethod: #x.#x                 // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 65
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 3, attributes: 6
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: iconst_2
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+EnclosingMethod: #x.#x                 // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 65
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 3, attributes: 6
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=2, args_size=2
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+            0       5     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: iconst_3
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 65
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 3, attributes: 6
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: iconst_4
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier_static
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 1, attributes: 4
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: iload_1
+         x: putfield      #x                 // Field value:I
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass;
+            0      10     1     x   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;             // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 1, attributes: 4
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: iconst_5
+         x: putfield      #x                 // Field value:I
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass;
+            0      10     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
+}
+InnerClasses:
+  public #x= #x of #x;                    // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 65
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 3, attributes: 6
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: bipush        7
+         x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;          // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass.getSupplier_static
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 1, attributes: 4
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: bipush        8
+         x: putfield      #x                 // Field value:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;           // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 4
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: bipush        6
+         x: putfield      #x                 // Field value:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+         x: dup
+         x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1."<init>":()V
+         x: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;             // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+  public static #x= #x of #x;           // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass extends com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  interfaces: 0, fields: 0, methods: 1, attributes: 4
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: aload_0
+         x: iload_1
+         x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass."<init>":(I)V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass;
+            0       6     1     x   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;             // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;            // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 4, attributes: 5
+  public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+         x: dup
+         x: aload_0
+        x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+        x: putfield      #x                 // Field mSupplier:Ljava/util/function/Supplier;
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      17     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.util.function.Supplier<java.lang.Integer> getSupplier();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+         x: dup
+         x: aload_0
+         x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+         x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       9     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+         x: dup
+         x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4."<init>":()V
+         x: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+         x: dup
+         x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2."<init>":()V
+         x: putstatic     #x                 // Field sSupplier:Ljava/util/function/Supplier;
+        x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  public static #x= #x of #x;            // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public #x= #x of #x;                  // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;          // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.class
+  Compiled from "TinyFrameworkPackageRedirect.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int foo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class com/supported/UnsupportedClass
+         x: dup
+         x: iload_0
+         x: invokespecial #x                 // Method com/supported/UnsupportedClass."<init>":(I)V
+         x: invokevirtual #x                 // Method com/supported/UnsupportedClass.getValue:()I
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      12     0 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkPackageRedirect.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.class
+  Compiled from "TinyFrameworkRenamedClassCaller.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int foo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
+         x: dup
+         x: iload_0
+         x: invokespecial #x                 // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed."<init>":(I)V
+         x: invokevirtual #x                 // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getValue:()I
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      12     0 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkRenamedClassCaller.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/packagetest/A.class
+  Compiled from "A.java"
+public class com.android.hoststubgen.test.tinyframework.packagetest.A
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/packagetest/A
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "A.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/A.class
+  Compiled from "A.java"
+public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/packagetest/sub/A
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "A.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C1.class
+  Compiled from "C1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.C1
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/C1
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "C1.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C2.class
+  Compiled from "C2.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.C2 extends com.android.hoststubgen.test.tinyframework.subclasstest.C1
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/C2
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/subclasstest/C1
+  interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "C2.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C3.class
+  Compiled from "C3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.C3 extends com.android.hoststubgen.test.tinyframework.subclasstest.C2
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/C3
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/subclasstest/C2
+  interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "C3.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/CA.class
+  Compiled from "CA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.CA
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/CA
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "CA.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/CB.class
+  Compiled from "CB.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.CB
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/CB
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "CB.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1.class
+  Compiled from "Class_C1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C1 extends com.android.hoststubgen.test.tinyframework.subclasstest.C1
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/subclasstest/C1
+  interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "Class_C1.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2.class
+  Compiled from "Class_C2.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C2 extends com.android.hoststubgen.test.tinyframework.subclasstest.C2
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/subclasstest/C2
+  interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "Class_C2.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3.class
+  Compiled from "Class_C3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C3 extends com.android.hoststubgen.test.tinyframework.subclasstest.C3
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/subclasstest/C3
+  interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "Class_C3.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1.class
+  Compiled from "Class_I1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1 implements com.android.hoststubgen.test.tinyframework.subclasstest.I1
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "Class_I1.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA.class
+  Compiled from "Class_I1_IA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1_IA implements com.android.hoststubgen.test.tinyframework.subclasstest.I1,com.android.hoststubgen.test.tinyframework.subclasstest.IA
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA
+  super_class: #x                         // java/lang/Object
+  interfaces: 2, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "Class_I1_IA.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2.class
+  Compiled from "Class_I2.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I2 implements com.android.hoststubgen.test.tinyframework.subclasstest.I2
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "Class_I2.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3.class
+  Compiled from "Class_I3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3 implements com.android.hoststubgen.test.tinyframework.subclasstest.I3
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "Class_I3.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I1.class
+  Compiled from "I1.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.I1
+  minor version: 0
+  major version: 65
+  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/I1
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "I1.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I2.class
+  Compiled from "I2.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.I2 extends com.android.hoststubgen.test.tinyframework.subclasstest.I1
+  minor version: 0
+  major version: 65
+  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/I2
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "I2.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I3.class
+  Compiled from "I3.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.I3 extends com.android.hoststubgen.test.tinyframework.subclasstest.I2
+  minor version: 0
+  major version: 65
+  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/I3
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "I3.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/IA.class
+  Compiled from "IA.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.IA
+  minor version: 0
+  major version: 65
+  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/IA
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "IA.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/IB.class
+  Compiled from "IB.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.IB
+  minor version: 0
+  major version: 65
+  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/IB
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "IB.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/supported/UnsupportedClass.class
+  Compiled from "UnsupportedClass.java"
+public class com.supported.UnsupportedClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/supported/UnsupportedClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 3
+  private final int mValue;
+    descriptor: I
+    flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public com.supported.UnsupportedClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: iload_1
+         x: putfield      #x                 // Field mValue:I
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/supported/UnsupportedClass;
+            0      10     1 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public int getValue();
+    descriptor: ()I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: getfield      #x                 // Field mValue:I
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/supported/UnsupportedClass;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/unsupported/UnsupportedClass.class
+  Compiled from "UnsupportedClass.java"
+public class com.unsupported.UnsupportedClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/unsupported/UnsupportedClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 3
+  public com.unsupported.UnsupportedClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String This class is not supported
+        x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      14     0  this   Lcom/unsupported/UnsupportedClass;
+            0      14     1 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public int getValue();
+    descriptor: ()I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String This class is not supported
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/unsupported/UnsupportedClass;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.class
+  Compiled from "TinyFrameworkToBeRenamed.java"
+public class rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 3
+  private final int mValue;
+    descriptor: I
+    flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: aload_0
+         x: iload_1
+         x: putfield      #x                 // Field mValue:I
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed;
+            0      10     1 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public int getValue();
+    descriptor: ()I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: getfield      #x                 // Field mValue:I
+         x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkToBeRenamed.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
new file mode 100644
index 0000000..49769e6
--- /dev/null
+++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
@@ -0,0 +1,4896 @@
+## Class: android/hosttest/annotation/HostSideTestClassLoadHook.class
+  Compiled from "HostSideTestClassLoadHook.java"
+public interface android.hosttest.annotation.HostSideTestClassLoadHook extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestClassLoadHook
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 2, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class android/hosttest/annotation/HostSideTestClassLoadHook
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public abstract java.lang.String value();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "HostSideTestClassLoadHook.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestKeep.class
+  Compiled from "HostSideTestKeep.java"
+public interface android.hosttest.annotation.HostSideTestKeep extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestKeep
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class android/hosttest/annotation/HostSideTestKeep
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "HostSideTestKeep.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+  x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestRedirect.class
+  Compiled from "HostSideTestRedirect.java"
+public interface android.hosttest.annotation.HostSideTestRedirect extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestRedirect
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class android/hosttest/annotation/HostSideTestRedirect
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "HostSideTestRedirect.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestRedirectionClass.class
+  Compiled from "HostSideTestRedirectionClass.java"
+public interface android.hosttest.annotation.HostSideTestRedirectionClass extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestRedirectionClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 2, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class android/hosttest/annotation/HostSideTestRedirectionClass
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public abstract java.lang.String value();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "HostSideTestRedirectionClass.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestRemove.class
+  Compiled from "HostSideTestRemove.java"
+public interface android.hosttest.annotation.HostSideTestRemove extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestRemove
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class android/hosttest/annotation/HostSideTestRemove
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "HostSideTestRemove.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+  x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestStaticInitializerKeep.class
+  Compiled from "HostSideTestStaticInitializerKeep.java"
+public interface android.hosttest.annotation.HostSideTestStaticInitializerKeep extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestStaticInitializerKeep
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class android/hosttest/annotation/HostSideTestStaticInitializerKeep
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "HostSideTestStaticInitializerKeep.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+  x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestSubstitute.class
+  Compiled from "HostSideTestSubstitute.java"
+public interface android.hosttest.annotation.HostSideTestSubstitute extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestSubstitute
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 2, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class android/hosttest/annotation/HostSideTestSubstitute
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public abstract java.lang.String suffix();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "HostSideTestSubstitute.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestThrow.class
+  Compiled from "HostSideTestThrow.java"
+public interface android.hosttest.annotation.HostSideTestThrow extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestThrow
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class android/hosttest/annotation/HostSideTestThrow
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "HostSideTestThrow.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+  x: #x(#x=[e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestWholeClassKeep.class
+  Compiled from "HostSideTestWholeClassKeep.java"
+public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 65
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestWholeClassKeep
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class android/hosttest/annotation/HostSideTestWholeClassKeep
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "HostSideTestWholeClassKeep.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy.class
+  Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 3, attributes: 4
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+         x: ldc           #x                 // String addTwo
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_0
+        x: iconst_2
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0     a   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;          // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub.class
+  Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 3, attributes: 4
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int addOne(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+         x: ldc           #x                 // String addOne
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_0
+        x: iconst_1
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0     a   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;           // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl.class
+  Compiled from "IPretendingAidl.java"
+public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl
+  minor version: 0
+  major version: 65
+  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 4
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+InnerClasses:
+  public static #x= #x of #x;           // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;          // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class
+  Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R$Nested
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/R$Nested
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 4
+  public static int[] ARRAY;
+    descriptor: [I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public com.android.hoststubgen.test.tinyframework.R$Nested();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/R$Nested
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/R$Nested;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/R$Nested
+         x: ldc           #x                 // String <clinit>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/R$Nested
+        x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+        x: iconst_1
+        x: newarray       int
+        x: dup
+        x: iconst_0
+        x: iconst_1
+        x: iastore
+        x: putstatic     #x                 // Field ARRAY:[I
+        x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;             // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/R.class
+  Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/R
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 4
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/R
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.R();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/R
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/R;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;           // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/R$Nested
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.class
+  Compiled from "TinyFrameworkAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 7, attributes: 3
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+         x: ldc           #x                 // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+        x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: iconst_1
+        x: putfield      #x                 // Field keep:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+         x: ldc           #x                 // String addOne
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_1
+        x: iconst_1
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+           11       4     1 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+         x: ldc           #x                 // String addTwo
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_1
+        x: iconst_2
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+           11       4     1 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+         x: ldc           #x                 // String nativeAddThree
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_0
+        x: iconst_3
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+         x: ldc           #x                 // String unsupportedMethod
+         x: ldc           #x                 // String ()Ljava/lang/String;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+        x: new           #x                 // class java/lang/RuntimeException
+        x: dup
+        x: ldc           #x                 // String Unreachable
+        x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        x: athrow
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestThrow
+
+  public int toBeIgnored();
+    descriptor: ()I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+         x: ldc           #x                 // String toBeIgnored
+         x: ldc           #x                 // String ()I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_0
+        x: ireturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestIgnore
+}
+SourceFile: "TinyFrameworkAnnotations.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+  x: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
+  Compiled from "TinyFrameworkClassLoadHook.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 3, attributes: 3
+  public static final java.util.Set<java.lang.Class<?>> sLoadedClasses;
+    descriptor: Ljava/util/Set;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/Set<Ljava/lang/Class<*>;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook();
+    descriptor: ()V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static void onClassLoaded(java.lang.Class<?>);
+    descriptor: (Ljava/lang/Class;)V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+         x: ldc           #x                 // String onClassLoaded
+         x: ldc           #x                 // String (Ljava/lang/Class;)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: getstatic     #x                 // Field sLoadedClasses:Ljava/util/Set;
+        x: aload_0
+        x: invokeinterface #x,  2           // InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z
+        x: pop
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      11     0 clazz   Ljava/lang/Class;
+      LocalVariableTypeTable:
+        Start  Length  Slot  Name   Signature
+           11      11     0 clazz   Ljava/lang/Class<*>;
+    Signature: #x                          // (Ljava/lang/Class<*>;)V
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+         x: ldc           #x                 // String <clinit>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+        x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+        x: new           #x                 // class java/util/HashSet
+        x: dup
+        x: invokespecial #x                 // Method java/util/HashSet."<init>":()V
+        x: putstatic     #x                 // Field sLoadedClasses:Ljava/util/Set;
+        x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkClassLoadHook.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations.class
+  Compiled from "TinyFrameworkClassWideAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 5, attributes: 3
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: iconst_1
+        x: putfield      #x                 // Field keep:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+         x: ldc           #x                 // String addOne
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_1
+        x: iconst_1
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+           11       4     1 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+         x: ldc           #x                 // String addTwo
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_1
+        x: iconst_2
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+           11       4     1 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+         x: ldc           #x                 // String unsupportedMethod
+         x: ldc           #x                 // String ()Ljava/lang/String;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+        x: new           #x                 // class java/lang/RuntimeException
+        x: dup
+        x: ldc           #x                 // String Unreachable
+        x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        x: athrow
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestThrow
+}
+SourceFile: "TinyFrameworkClassWideAnnotations.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.class
+  Compiled from "TinyFrameworkClassWithInitializerDefault.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 0, attributes: 3
+  public static boolean sInitialized;
+    descriptor: Z
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static java.lang.Object sObject;
+    descriptor: Ljava/lang/Object;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+}
+SourceFile: "TinyFrameworkClassWithInitializerDefault.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub.class
+  Compiled from "TinyFrameworkClassWithInitializerStub.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerStub
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 1, attributes: 3
+  public static boolean sInitialized;
+    descriptor: Z
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static java.lang.Object sObject;
+    descriptor: Ljava/lang/Object;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+         x: ldc           #x                 // String <clinit>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+        x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+        x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+        x: ldc           #x                 // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+        x: iconst_1
+        x: putstatic     #x                 // Field sInitialized:Z
+        x: new           #x                  // class java/lang/Object
+        x: dup
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: putstatic     #x                 // Field sObject:Ljava/lang/Object;
+        x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkClassWithInitializerStub.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+  x: #x()
+    android.hosttest.annotation.HostSideTestStaticInitializerKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.class
+  Compiled from "TinyFrameworkEnumComplex.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex>
+  minor version: 0
+  major version: 65
+  flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+  super_class: #x                         // java/lang/Enum
+  interfaces: 0, fields: 6, methods: 7, attributes: 4
+  public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex GREEN;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex BLUE;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private final java.lang.String mLongName;
+    descriptor: Ljava/lang/String;
+    flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private final java.lang.String mShortName;
+    descriptor: Ljava/lang/String;
+    flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $VALUES;
+    descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] values();
+    descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+         x: ldc           #x                 // String values
+         x: ldc           #x                 // String ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: getstatic     #x                 // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: invokevirtual #x                 // Method "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;".clone:()Ljava/lang/Object;
+        x: checkcast     #x                 // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;"
+        x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex valueOf(java.lang.String);
+    descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+         x: ldc           #x                 // String valueOf
+         x: ldc           #x                 // String (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+        x: aload_0
+        x: invokestatic  #x                 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+        x: checkcast     #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      10     0  name   Ljava/lang/String;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    MethodParameters:
+      Name                           Flags
+      <no name>                      mandated
+
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
+    descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=4, locals=5, args_size=5
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: aload_1
+        x: iload_2
+        x: invokespecial #x                 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
+        x: aload_0
+        x: aload_3
+        x: putfield      #x                 // Field mLongName:Ljava/lang/String;
+        x: aload_0
+        x: aload         4
+        x: putfield      #x                 // Field mShortName:Ljava/lang/String;
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      18     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+           11      18     3 longName   Ljava/lang/String;
+           11      18     4 shortName   Ljava/lang/String;
+    Signature: #x                          // (Ljava/lang/String;Ljava/lang/String;)V
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+    MethodParameters:
+      Name                           Flags
+      <no name>                      synthetic
+      <no name>                      synthetic
+      <no name>
+      <no name>
+
+  public java.lang.String getLongName();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+         x: ldc           #x                 // String getLongName
+         x: ldc           #x                 // String ()Ljava/lang/String;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: getfield      #x                 // Field mLongName:Ljava/lang/String;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public java.lang.String getShortName();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+         x: ldc           #x                 // String getShortName
+         x: ldc           #x                 // String ()Ljava/lang/String;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: getfield      #x                 // Field mShortName:Ljava/lang/String;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $values();
+    descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+         x: ldc           #x                 // String $values
+         x: ldc           #x                 // String ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_3
+        x: anewarray     #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+        x: dup
+        x: iconst_0
+        x: getstatic     #x                 // Field RED:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: aastore
+        x: dup
+        x: iconst_1
+        x: getstatic     #x                 // Field GREEN:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: aastore
+        x: dup
+        x: iconst_2
+        x: getstatic     #x                 // Field BLUE:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: aastore
+        x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=6, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+         x: ldc           #x                 // String <clinit>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+        x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+        x: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+        x: dup
+        x: ldc           #x                 // String RED
+        x: iconst_0
+        x: ldc           #x                 // String Red
+        x: ldc           #x                 // String R
+        x: invokespecial #x                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+        x: putstatic     #x                 // Field RED:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+        x: dup
+        x: ldc           #x                 // String GREEN
+        x: iconst_1
+        x: ldc           #x                 // String Green
+        x: ldc           #x                 // String G
+        x: invokespecial #x                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+        x: putstatic     #x                 // Field GREEN:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+        x: dup
+        x: ldc           #x                 // String BLUE
+        x: iconst_2
+        x: ldc           #x                 // String Blue
+        x: ldc           #x                // String B
+        x: invokespecial #x                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+        x: putstatic     #x                 // Field BLUE:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: invokestatic  #x                // Method $values:()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: putstatic     #x                 // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+        x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+Signature: #x                           // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;>;
+SourceFile: "TinyFrameworkEnumComplex.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.class
+  Compiled from "TinyFrameworkEnumSimple.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple>
+  minor version: 0
+  major version: 65
+  flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+  super_class: #x                         // java/lang/Enum
+  interfaces: 0, fields: 3, methods: 5, attributes: 4
+  public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple DOG;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $VALUES;
+    descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] values();
+    descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+         x: ldc           #x                 // String values
+         x: ldc           #x                 // String ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: getstatic     #x                 // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+        x: invokevirtual #x                 // Method "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;".clone:()Ljava/lang/Object;
+        x: checkcast     #x                 // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;"
+        x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple valueOf(java.lang.String);
+    descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+         x: ldc           #x                 // String valueOf
+         x: ldc           #x                 // String (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+        x: aload_0
+        x: invokestatic  #x                 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+        x: checkcast     #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      10     0  name   Ljava/lang/String;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    MethodParameters:
+      Name                           Flags
+      <no name>                      mandated
+
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
+    descriptor: (Ljava/lang/String;I)V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=4, locals=3, args_size=3
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String (Ljava/lang/String;I)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: aload_1
+        x: iload_2
+        x: invokespecial #x                 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       7     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    Signature: #x                          // ()V
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    MethodParameters:
+      Name                           Flags
+      <no name>                      synthetic
+      <no name>                      synthetic
+
+  private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
+    descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+         x: ldc           #x                 // String $values
+         x: ldc           #x                 // String ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_2
+        x: anewarray     #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+        x: dup
+        x: iconst_0
+        x: getstatic     #x                 // Field CAT:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+        x: aastore
+        x: dup
+        x: iconst_1
+        x: getstatic     #x                 // Field DOG:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+        x: aastore
+        x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+         x: ldc           #x                 // String <clinit>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+        x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+        x: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+        x: dup
+        x: ldc           #x                 // String CAT
+        x: iconst_0
+        x: invokespecial #x                 // Method "<init>":(Ljava/lang/String;I)V
+        x: putstatic     #x                 // Field CAT:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+        x: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+        x: dup
+        x: ldc           #x                 // String DOG
+        x: iconst_1
+        x: invokespecial #x                 // Method "<init>":(Ljava/lang/String;I)V
+        x: putstatic     #x                 // Field DOG:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+        x: invokestatic  #x                 // Method $values:()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+        x: putstatic     #x                 // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+        x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+Signature: #x                           // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;>;
+SourceFile: "TinyFrameworkEnumSimple.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
+  Compiled from "TinyFrameworkExceptionTester.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 3, attributes: 3
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int testException();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+         x: ldc           #x                 // String testException
+         x: ldc           #x                 // String ()I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: new           #x                 // class java/lang/IllegalStateException
+        x: dup
+        x: ldc           #x                 // String Inner exception
+        x: invokespecial #x                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
+        x: athrow
+        x: astore_0
+        x: new           #x                 // class java/lang/RuntimeException
+        x: dup
+        x: ldc           #x                 // String Outer exception
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V
+        x: athrow
+      Exception table:
+         from    to  target type
+            11    21    21   Class java/lang/Exception
+      StackMapTable: number_of_entries = 1
+        frame_type = 85 /* same_locals_1_stack_item */
+          stack = [ class java/lang/Exception ]
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           22      11     0     e   Ljava/lang/Exception;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkExceptionTester.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.class
+  Compiled from "TinyFrameworkForTextPolicy.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 15, attributes: 2
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+        x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: iconst_1
+        x: putfield      #x                 // Field stub:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String addOne
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_1
+        x: iconst_1
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+           11       4     1 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.String toBeIgnoredObj();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String toBeIgnoredObj
+         x: ldc           #x                 // String ()Ljava/lang/String;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aconst_null
+        x: areturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public void toBeIgnoredV();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String toBeIgnoredV
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: return
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public boolean toBeIgnoredZ();
+    descriptor: ()Z
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String toBeIgnoredZ
+         x: ldc           #x                 // String ()Z
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_0
+        x: ireturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public byte toBeIgnoredB();
+    descriptor: ()B
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String toBeIgnoredB
+         x: ldc           #x                 // String ()B
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_0
+        x: ireturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public char toBeIgnoredC();
+    descriptor: ()C
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String toBeIgnoredC
+         x: ldc           #x                 // String ()C
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_0
+        x: ireturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public short toBeIgnoredS();
+    descriptor: ()S
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String toBeIgnoredS
+         x: ldc           #x                 // String ()S
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_0
+        x: ireturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public int toBeIgnoredI();
+    descriptor: ()I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String toBeIgnoredI
+         x: ldc           #x                 // String ()I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_0
+        x: ireturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public float toBeIgnoredF();
+    descriptor: ()F
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String toBeIgnoredF
+         x: ldc           #x                 // String ()F
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: fconst_0
+        x: freturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public double toBeIgnoredD();
+    descriptor: ()D
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String toBeIgnoredD
+         x: ldc           #x                 // String ()D
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: dconst_0
+        x: dreturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String addTwo
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_1
+        x: iconst_2
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+           11       4     1 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String nativeAddThree
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_0
+        x: iconst_3
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String unsupportedMethod
+         x: ldc           #x                 // String ()Ljava/lang/String;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+        x: new           #x                 // class java/lang/RuntimeException
+        x: dup
+        x: ldc           #x                 // String Unreachable
+        x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        x: athrow
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkForTextPolicy.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.class
+  Compiled from "TinyFrameworkLambdas.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nested
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 8, attributes: 6
+  public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nested();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+        x: putfield      #x                 // Field mSupplier:Ljava/util/function/Supplier;
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      14     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public java.util.function.Supplier<java.lang.Integer> getSupplier();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+         x: ldc           #x                 // String getSupplier
+         x: ldc           #x                 // String ()Ljava/util/function/Supplier;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested;
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+         x: ldc           #x                 // String getSupplier_static
+         x: ldc           #x                 // String ()Ljava/util/function/Supplier;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+        x: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static java.lang.Integer lambda$getSupplier_static$3();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+         x: ldc           #x                 // String lambda$getSupplier_static$3
+         x: ldc           #x                 // String ()Ljava/lang/Integer;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: bipush        8
+        x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static java.lang.Integer lambda$getSupplier$2();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+         x: ldc           #x                 // String lambda$getSupplier$2
+         x: ldc           #x                 // String ()Ljava/lang/Integer;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: bipush        7
+        x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static java.lang.Integer lambda$static$1();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+         x: ldc           #x                 // String lambda$static$1
+         x: ldc           #x                 // String ()Ljava/lang/Integer;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: bipush        6
+        x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static java.lang.Integer lambda$new$0();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+         x: ldc           #x                 // String lambda$new$0
+         x: ldc           #x                 // String ()Ljava/lang/Integer;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_5
+        x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+         x: ldc           #x                 // String <clinit>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+        x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+        x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+        x: putstatic     #x                 // Field sSupplier:Ljava/util/function/Supplier;
+        x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;            // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+  public static final #x= #x of #x;    // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+SourceFile: "TinyFrameworkLambdas.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+  x: #x()
+    android.hosttest.annotation.HostSideTestStaticInitializerKeep
+BootstrapMethods:
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$new$0:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$getSupplier$2:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$getSupplier_static$3:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.lambda$static$1:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.class
+  Compiled from "TinyFrameworkLambdas.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 8, attributes: 6
+  public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+        x: putfield      #x                 // Field mSupplier:Ljava/util/function/Supplier;
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      14     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public java.util.function.Supplier<java.lang.Integer> getSupplier();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+         x: ldc           #x                 // String getSupplier
+         x: ldc           #x                 // String ()Ljava/util/function/Supplier;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas;
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+         x: ldc           #x                 // String getSupplier_static
+         x: ldc           #x                 // String ()Ljava/util/function/Supplier;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+        x: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static java.lang.Integer lambda$getSupplier_static$3();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+         x: ldc           #x                 // String lambda$getSupplier_static$3
+         x: ldc           #x                 // String ()Ljava/lang/Integer;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_4
+        x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static java.lang.Integer lambda$getSupplier$2();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+         x: ldc           #x                 // String lambda$getSupplier$2
+         x: ldc           #x                 // String ()Ljava/lang/Integer;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_3
+        x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static java.lang.Integer lambda$static$1();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+         x: ldc           #x                 // String lambda$static$1
+         x: ldc           #x                 // String ()Ljava/lang/Integer;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_2
+        x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static java.lang.Integer lambda$new$0();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+         x: ldc           #x                 // String lambda$new$0
+         x: ldc           #x                 // String ()Ljava/lang/Integer;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_1
+        x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+         x: ldc           #x                 // String <clinit>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+        x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+        x: invokedynamic #x,  0             // InvokeDynamic #x:get:()Ljava/util/function/Supplier;
+        x: putstatic     #x                 // Field sSupplier:Ljava/util/function/Supplier;
+        x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;           // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
+  public static final #x= #x of #x;    // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+SourceFile: "TinyFrameworkLambdas.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestKeep
+  x: #x()
+    android.hosttest.annotation.HostSideTestStaticInitializerKeep
+BootstrapMethods:
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$new$0:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$getSupplier$2:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$getSupplier_static$3:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()Ljava/lang/Object;
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas.lambda$static$1:()Ljava/lang/Integer;
+      #x ()Ljava/lang/Integer;
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class
+  Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 4, attributes: 4
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static void startThread(java.lang.Thread);
+    descriptor: (Ljava/lang/Thread;)V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+         x: ldc           #x                 // String startThread
+         x: ldc           #x                 // String (Ljava/lang/Thread;)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: iconst_1
+        x: invokevirtual #x                 // Method java/lang/Thread.setDaemon:(Z)V
+        x: aload_0
+        x: invokevirtual #x                 // Method java/lang/Thread.start:()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      10     0 thread   Ljava/lang/Thread;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int add(int, int);
+    descriptor: (II)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+         x: ldc           #x                 // String add
+         x: ldc           #x                 // String (II)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_0
+        x: iload_1
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0     a   I
+           11       4     1     b   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;           // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.class
+  Compiled from "TinyFrameworkMethodCallReplace.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 5, attributes: 6
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static boolean nonStaticMethodCallReplaceTester() throws java.lang.Exception;
+    descriptor: ()Z
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=2, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+         x: ldc           #x                 // String nonStaticMethodCallReplaceTester
+         x: ldc           #x                 // String ()Z
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: new           #x                 // class java/util/concurrent/atomic/AtomicBoolean
+        x: dup
+        x: iconst_0
+        x: invokespecial #x                 // Method java/util/concurrent/atomic/AtomicBoolean."<init>":(Z)V
+        x: astore_0
+        x: new           #x                 // class java/lang/Thread
+        x: dup
+        x: aload_0
+        x: invokedynamic #x,  0             // InvokeDynamic #x:run:(Ljava/util/concurrent/atomic/AtomicBoolean;)Ljava/lang/Runnable;
+        x: invokespecial #x                 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
+        x: astore_1
+        x: aload_1
+        x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.startThread:(Ljava/lang/Thread;)V
+        x: aload_1
+        x: invokevirtual #x                 // Method java/lang/Thread.join:()V
+        x: aload_0
+        x: invokevirtual #x                 // Method java/util/concurrent/atomic/AtomicBoolean.get:()Z
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           20      27     0    ab   Ljava/util/concurrent/atomic/AtomicBoolean;
+           34      13     1    th   Ljava/lang/Thread;
+    Exceptions:
+      throws java.lang.Exception
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int staticMethodCallReplaceTester();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+         x: ldc           #x                 // String staticMethodCallReplaceTester
+         x: ldc           #x                 // String ()I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_1
+        x: iconst_2
+        x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.add:(II)I
+        x: ireturn
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static void lambda$nonStaticMethodCallReplaceTester$0(java.util.concurrent.atomic.AtomicBoolean);
+    descriptor: (Ljava/util/concurrent/atomic/AtomicBoolean;)V
+    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+         x: ldc           #x                 // String lambda$nonStaticMethodCallReplaceTester$0
+         x: ldc           #x                 // String (Ljava/util/concurrent/atomic/AtomicBoolean;)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokestatic  #x                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
+        x: invokevirtual #x                // Method java/lang/Thread.isDaemon:()Z
+        x: invokevirtual #x                // Method java/util/concurrent/atomic/AtomicBoolean.set:(Z)V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      11     0    ab   Ljava/util/concurrent/atomic/AtomicBoolean;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;           // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
+  public static final #x= #x of #x;    // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
+SourceFile: "TinyFrameworkMethodCallReplace.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+BootstrapMethods:
+  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+    Method arguments:
+      #x ()V
+      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.lambda$nonStaticMethodCallReplaceTester$0:(Ljava/util/concurrent/atomic/AtomicBoolean;)V
+      #x ()V
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
+  Compiled from "TinyFrameworkNative.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 15, attributes: 3
+  int value;
+    descriptor: I
+    flags: (0x0000)
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int nativeAddTwo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+         x: ldc           #x                 // String nativeAddTwo
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_0
+        x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+        x: ireturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRedirect
+
+  public static int nativeAddTwo_should_be_like_this(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+         x: ldc           #x                 // String nativeAddTwo_should_be_like_this
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_0
+        x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0   arg   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static long nativeLongPlus(long, long);
+    descriptor: (JJ)J
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=4, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+         x: ldc           #x                 // String nativeLongPlus
+         x: ldc           #x                 // String (JJ)J
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: lload_0
+        x: lload_2
+        x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+        x: lreturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRedirect
+
+  public static long nativeLongPlus_should_be_like_this(long, long);
+    descriptor: (JJ)J
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=4, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+         x: ldc           #x                 // String nativeLongPlus_should_be_like_this
+         x: ldc           #x                 // String (JJ)J
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: lload_0
+        x: lload_2
+        x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+        x: lreturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       6     0  arg1   J
+           11       6     2  arg2   J
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public void setValue(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+         x: ldc           #x                 // String setValue
+         x: ldc           #x                 // String (I)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: iload_1
+        x: putfield      #x                 // Field value:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+           11       6     1     v   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public int nativeNonStaticAddToValue(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+         x: ldc           #x                 // String nativeNonStaticAddToValue
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: iload_1
+        x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeNonStaticAddToValue:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I
+        x: ireturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRedirect
+
+  public int nativeNonStaticAddToValue_should_be_like_this(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+         x: ldc           #x                 // String nativeNonStaticAddToValue_should_be_like_this
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: iload_1
+        x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeNonStaticAddToValue:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+           11       6     1   arg   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static void nativeStillNotSupported();
+    descriptor: ()V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+         x: ldc           #x                 // String nativeStillNotSupported
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+        x: new           #x                 // class java/lang/RuntimeException
+        x: dup
+        x: ldc           #x                 // String Unreachable
+        x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        x: athrow
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestThrow
+
+  public static native void nativeStillKeep();
+    descriptor: ()V
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static void nativeStillNotSupported_should_be_like_this();
+    descriptor: ()V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+         x: ldc           #x                 // String nativeStillNotSupported_should_be_like_this
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: new           #x                 // class java/lang/RuntimeException
+        x: dup
+        x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+        x: athrow
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static byte nativeBytePlus(byte, byte);
+    descriptor: (BB)B
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+         x: ldc           #x                 // String nativeBytePlus
+         x: ldc           #x                 // String (BB)B
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_0
+        x: iload_1
+        x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeBytePlus:(BB)B
+        x: ireturn
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRedirect
+
+  public void notNativeRedirected();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+         x: ldc           #x                 // String notNativeRedirected
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokestatic  #x                // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.notNativeRedirected:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;)V
+        x: return
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRedirect
+
+  public static void notNativeStaticRedirected();
+    descriptor: ()V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+         x: ldc           #x                // String notNativeStaticRedirected
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: invokestatic  #x                // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.notNativeStaticRedirected:()V
+        x: return
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestRedirect
+}
+SourceFile: "TinyFrameworkNative.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+  x: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestRedirectionClass(
+      value="TinyFrameworkNative_host"
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.class
+  Compiled from "TinyFrameworkNative_host.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 8, attributes: 3
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int nativeAddTwo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+         x: ldc           #x                 // String nativeAddTwo
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_0
+        x: iconst_2
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0   arg   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static long nativeLongPlus(long, long);
+    descriptor: (JJ)J
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=4, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+         x: ldc           #x                 // String nativeLongPlus
+         x: ldc           #x                 // String (JJ)J
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: lload_0
+        x: lload_2
+        x: ladd
+        x: lreturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0  arg1   J
+           11       4     2  arg2   J
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int nativeNonStaticAddToValue(com.android.hoststubgen.test.tinyframework.TinyFrameworkNative, int);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+         x: ldc           #x                 // String nativeNonStaticAddToValue
+         x: ldc           #x                 // String (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: getfield      #x                 // Field com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.value:I
+        x: iload_1
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       7     0 source   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+           11       7     1   arg   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static byte nativeBytePlus(byte, byte);
+    descriptor: (BB)B
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+         x: ldc           #x                 // String nativeBytePlus
+         x: ldc           #x                 // String (BB)B
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_0
+        x: iload_1
+        x: iadd
+        x: i2b
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  arg1   B
+           11       5     1  arg2   B
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static void notNativeRedirected(com.android.hoststubgen.test.tinyframework.TinyFrameworkNative);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;)V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+         x: ldc           #x                 // String notNativeRedirected
+         x: ldc           #x                 // String (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       1     0 source   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static void notNativeStaticRedirected();
+    descriptor: ()V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+         x: ldc           #x                 // String notNativeStaticRedirected
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkNative_host.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 65
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 4, attributes: 6
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0000)
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+           11       5     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Integer;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_1
+        x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Object;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+EnclosingMethod: #x.#x                 // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 65
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 4, attributes: 6
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Integer;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_2
+        x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Object;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+EnclosingMethod: #x.#x                 // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 65
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 4, attributes: 6
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0000)
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+           11       5     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Integer;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_3
+        x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Object;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 65
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 4, attributes: 6
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Integer;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_4
+        x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Object;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier_static
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 4
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String (I)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: iload_1
+        x: putfield      #x                 // Field value:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass;
+           11      10     1     x   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;           // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 4
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: iconst_5
+        x: putfield      #x                 // Field value:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass;
+           11      10     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
+}
+InnerClasses:
+  public #x= #x of #x;                  // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 65
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 4, attributes: 6
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Integer;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: bipush        7
+        x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Object;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;          // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass.getSupplier_static
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 4
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: bipush        8
+        x: putfield      #x                 // Field value:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      11     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;          // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 3, attributes: 4
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: bipush        6
+        x: putfield      #x                 // Field value:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      11     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+         x: ldc           #x                 // String getSupplier_static
+         x: ldc           #x                 // String ()Ljava/util/function/Supplier;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+        x: dup
+        x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1."<init>":()V
+        x: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;           // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+  public static #x= #x of #x;           // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass extends com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  interfaces: 0, fields: 0, methods: 2, attributes: 4
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String (I)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: iload_1
+        x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass."<init>":(I)V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass;
+           11       6     1     x   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  public static #x= #x of #x;           // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 4, attributes: 5
+  public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+        x: dup
+        x: aload_0
+        x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+        x: putfield      #x                 // Field mSupplier:Ljava/util/function/Supplier;
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      17     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public java.util.function.Supplier<java.lang.Integer> getSupplier();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+         x: ldc           #x                 // String getSupplier
+         x: ldc           #x                 // String ()Ljava/util/function/Supplier;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+        x: dup
+        x: aload_0
+        x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       9     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+         x: ldc           #x                 // String getSupplier_static
+         x: ldc           #x                 // String ()Ljava/util/function/Supplier;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+        x: dup
+        x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4."<init>":()V
+        x: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+         x: ldc           #x                 // String <clinit>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+        x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+        x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+        x: dup
+        x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2."<init>":()V
+        x: putstatic     #x                 // Field sSupplier:Ljava/util/function/Supplier;
+        x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+InnerClasses:
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  public static #x= #x of #x;            // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public #x= #x of #x;                  // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;          // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.class
+  Compiled from "TinyFrameworkPackageRedirect.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 3, attributes: 3
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int foo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+         x: ldc           #x                 // String foo
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: new           #x                 // class com/supported/UnsupportedClass
+        x: dup
+        x: iload_0
+        x: invokespecial #x                 // Method com/supported/UnsupportedClass."<init>":(I)V
+        x: invokevirtual #x                 // Method com/supported/UnsupportedClass.getValue:()I
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      12     0 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkPackageRedirect.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.class
+  Compiled from "TinyFrameworkRenamedClassCaller.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 3, attributes: 3
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public static int foo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller
+         x: ldc           #x                 // String foo
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: new           #x                 // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
+        x: dup
+        x: iload_0
+        x: invokespecial #x                 // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed."<init>":(I)V
+        x: invokevirtual #x                 // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getValue:()I
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      12     0 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkRenamedClassCaller.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/packagetest/A.class
+  Compiled from "A.java"
+public class com.android.hoststubgen.test.tinyframework.packagetest.A
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/packagetest/A
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/packagetest/A
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "A.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/A.class
+  Compiled from "A.java"
+public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/packagetest/sub/A
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/packagetest/sub/A
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "A.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C1.class
+  Compiled from "C1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.C1
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/C1
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/subclasstest/C1
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "C1.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C2.class
+  Compiled from "C2.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.C2 extends com.android.hoststubgen.test.tinyframework.subclasstest.C1
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/C2
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/subclasstest/C1
+  interfaces: 0, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/subclasstest/C2
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "C2.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C3.class
+  Compiled from "C3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.C3 extends com.android.hoststubgen.test.tinyframework.subclasstest.C2
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/C3
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/subclasstest/C2
+  interfaces: 0, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/subclasstest/C3
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "C3.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/CA.class
+  Compiled from "CA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.CA
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/CA
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/subclasstest/CA
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "CA.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/CB.class
+  Compiled from "CB.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.CB
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/CB
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/subclasstest/CB
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "CB.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1.class
+  Compiled from "Class_C1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C1 extends com.android.hoststubgen.test.tinyframework.subclasstest.C1
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/subclasstest/C1
+  interfaces: 0, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "Class_C1.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2.class
+  Compiled from "Class_C2.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C2 extends com.android.hoststubgen.test.tinyframework.subclasstest.C2
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/subclasstest/C2
+  interfaces: 0, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "Class_C2.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3.class
+  Compiled from "Class_C3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C3 extends com.android.hoststubgen.test.tinyframework.subclasstest.C3
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/subclasstest/C3
+  interfaces: 0, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "Class_C3.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1.class
+  Compiled from "Class_I1.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1 implements com.android.hoststubgen.test.tinyframework.subclasstest.I1
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "Class_I1.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA.class
+  Compiled from "Class_I1_IA.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1_IA implements com.android.hoststubgen.test.tinyframework.subclasstest.I1,com.android.hoststubgen.test.tinyframework.subclasstest.IA
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA
+  super_class: #x                         // java/lang/Object
+  interfaces: 2, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "Class_I1_IA.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2.class
+  Compiled from "Class_I2.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I2 implements com.android.hoststubgen.test.tinyframework.subclasstest.I2
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "Class_I2.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3.class
+  Compiled from "Class_I3.java"
+public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3 implements com.android.hoststubgen.test.tinyframework.subclasstest.I3
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "Class_I3.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I1.class
+  Compiled from "I1.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.I1
+  minor version: 0
+  major version: 65
+  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/I1
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/subclasstest/I1
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "I1.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I2.class
+  Compiled from "I2.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.I2 extends com.android.hoststubgen.test.tinyframework.subclasstest.I1
+  minor version: 0
+  major version: 65
+  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/I2
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/subclasstest/I2
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "I2.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I3.class
+  Compiled from "I3.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.I3 extends com.android.hoststubgen.test.tinyframework.subclasstest.I2
+  minor version: 0
+  major version: 65
+  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/I3
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/subclasstest/I3
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "I3.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/IA.class
+  Compiled from "IA.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.IA
+  minor version: 0
+  major version: 65
+  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/IA
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/subclasstest/IA
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "IA.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/android/hoststubgen/test/tinyframework/subclasstest/IB.class
+  Compiled from "IB.java"
+public interface com.android.hoststubgen.test.tinyframework.subclasstest.IB
+  minor version: 0
+  major version: 65
+  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/subclasstest/IB
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/subclasstest/IB
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "IB.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+## Class: com/supported/UnsupportedClass.class
+  Compiled from "UnsupportedClass.java"
+public class com.supported.UnsupportedClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/supported/UnsupportedClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 3, attributes: 3
+  private final int mValue;
+    descriptor: I
+    flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/supported/UnsupportedClass
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.supported.UnsupportedClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/supported/UnsupportedClass
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String (I)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: iload_1
+        x: putfield      #x                 // Field mValue:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      10     0  this   Lcom/supported/UnsupportedClass;
+           11      10     1 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public int getValue();
+    descriptor: ()I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/supported/UnsupportedClass
+         x: ldc           #x                 // String getValue
+         x: ldc           #x                 // String ()I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: getfield      #x                 // Field mValue:I
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/supported/UnsupportedClass;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/unsupported/UnsupportedClass.class
+  Compiled from "UnsupportedClass.java"
+public class com.unsupported.UnsupportedClass
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/unsupported/UnsupportedClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 3, attributes: 3
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/unsupported/UnsupportedClass
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.unsupported.UnsupportedClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/unsupported/UnsupportedClass
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String (I)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: new           #x                 // class java/lang/RuntimeException
+        x: dup
+        x: ldc           #x                 // String This class is not supported
+        x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      14     0  this   Lcom/unsupported/UnsupportedClass;
+           11      14     1 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public int getValue();
+    descriptor: ()I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/unsupported/UnsupportedClass
+         x: ldc           #x                 // String getValue
+         x: ldc           #x                 // String ()I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: new           #x                 // class java/lang/RuntimeException
+        x: dup
+        x: ldc           #x                 // String This class is not supported
+        x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      10     0  this   Lcom/unsupported/UnsupportedClass;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.class
+  Compiled from "TinyFrameworkToBeRenamed.java"
+public class rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed
+  minor version: 0
+  major version: 65
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 3, attributes: 3
+  private final int mValue;
+    descriptor: I
+    flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String (I)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: iload_1
+        x: putfield      #x                 // Field mValue:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed;
+           11      10     1 value   I
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+  public int getValue();
+    descriptor: ()I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
+         x: ldc           #x                 // String getValue
+         x: ldc           #x                 // String ()I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: getfield      #x                 // Field mValue:I
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+}
+SourceFile: "TinyFrameworkToBeRenamed.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py
index 7a7de35..88fa492 100755
--- a/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py
+++ b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py
@@ -20,18 +20,23 @@
 import unittest
 import subprocess
 
-GOLDEN_DIR = 'golden-output'
+GOLDEN_DIRS = [
+    'golden-output',
+    'golden-output.RELEASE_TARGET_JAVA_21',
+]
+
 
 # Run diff.
 def run_diff(file1, file2):
-    command = ['diff', '-u', '--ignore-blank-lines', '--ignore-space-change', file1, file2]
+    command = ['diff', '-u', '--ignore-blank-lines',
+               '--ignore-space-change', file1, file2]
     print(' '.join(command))
-    result = subprocess.run(command, stderr = sys.stdout)
+    result = subprocess.run(command, stderr=sys.stdout)
 
     success = result.returncode == 0
 
     if success:
-        print(f'No diff found.')
+        print('No diff found.')
     else:
         print(f'Fail: {file1} and {file2} are different.')
 
@@ -39,27 +44,42 @@
 
 
 # Check one golden file.
-def check_one_file(filename):
+def check_one_file(golden_dir, filename):
     print(f'= Checking file: {filename}')
-    return run_diff(os.path.join(GOLDEN_DIR, filename), filename)
+    return run_diff(os.path.join(golden_dir, filename), filename)
+
 
 class TestWithGoldenOutput(unittest.TestCase):
 
     # Test to check the generated jar files to the golden output.
+    # Depending on build flags, the golden output may differ in expected ways.
+    # So only expect the files to match one of the possible golden outputs.
     def test_compare_to_golden(self):
-        self.skipTest("test cannot handle multiple images (see b/378470825)")
-        files = os.listdir(GOLDEN_DIR)
-        files.sort()
+        success = False
 
-        print(f"Golden files: {files}")
-        success = True
-
-        for file in files:
-            if not check_one_file(file):
-                success = False
+        for golden_dir in GOLDEN_DIRS:
+            if self.matches_golden(golden_dir):
+                success = True
+                print(f"Test passes for dir: {golden_dir}")
+                break
 
         if not success:
-            self.fail('Some files are different. See stdout log for more details.')
+            self.fail('Some files are different. ' +
+                      'See stdout log for more details.')
+
+    def matches_golden(self, golden_dir):
+        files = os.listdir(golden_dir)
+        files.sort()
+
+        print(f"Golden files for {golden_dir}: {files}")
+        match_success = True
+
+        for file in files:
+            if not check_one_file(golden_dir, file):
+                match_success = False
+
+        return match_success
+
 
 if __name__ == "__main__":
     unittest.main(verbosity=2)
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index 2808056..a0b989b 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -55,16 +55,6 @@
 }
 
 flag {
-    name: "compute_window_changes_on_a11y_v2"
-    namespace: "accessibility"
-    description: "Computes accessibility window changes in accessibility instead of wm package."
-    bug: "322444245"
-    metadata {
-        purpose: PURPOSE_BUGFIX
-    }
-}
-
-flag {
     name: "deprecate_package_list_observer"
     namespace: "accessibility"
     description: "Stops using the deprecated PackageListObserver."
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index d6fc6e4..e1b6c9c 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -409,10 +409,6 @@
         final int eventSource = event.getSource();
         final int displayId = event.getDisplayId();
         if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) == 0) {
-            if (!Flags.doNotResetKeyEventState()) {
-                state.reset();
-                clearEventStreamHandler(displayId, eventSource);
-            }
             if (DEBUG) {
                 Slog.d(TAG, "Not processing event " + event);
             }
@@ -1180,18 +1176,8 @@
     }
 
     private boolean anyServiceWantsGenericMotionEvent(MotionEvent event) {
-        if (Flags.alwaysAllowObservingTouchEvents()) {
-            final boolean isTouchEvent = event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN);
-            if (isTouchEvent && !canShareGenericTouchEvent()) {
-                return false;
-            }
-            final int eventSourceWithoutClass = event.getSource() & ~InputDevice.SOURCE_CLASS_MASK;
-            return (mCombinedGenericMotionEventSources & eventSourceWithoutClass) != 0;
-        }
-        // Disable SOURCE_TOUCHSCREEN generic event interception if any service is performing
-        // touch exploration.
-        if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)
-                && (mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) {
+        final boolean isTouchEvent = event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN);
+        if (isTouchEvent && !canShareGenericTouchEvent()) {
             return false;
         }
         final int eventSourceWithoutClass = event.getSource() & ~InputDevice.SOURCE_CLASS_MASK;
@@ -1199,21 +1185,8 @@
     }
 
     private boolean anyServiceWantsToObserveMotionEvent(MotionEvent event) {
-        if (Flags.alwaysAllowObservingTouchEvents()) {
-            final int eventSourceWithoutClass = event.getSource() & ~InputDevice.SOURCE_CLASS_MASK;
-            return (mCombinedMotionEventObservedSources & eventSourceWithoutClass) != 0;
-        }
-        // Disable SOURCE_TOUCHSCREEN generic event interception if any service is performing
-        // touch exploration.
-        if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)
-                && (mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) {
-            return false;
-        }
         final int eventSourceWithoutClass = event.getSource() & ~InputDevice.SOURCE_CLASS_MASK;
-        return (mCombinedGenericMotionEventSources
-                & mCombinedMotionEventObservedSources
-                & eventSourceWithoutClass)
-                != 0;
+        return (mCombinedMotionEventObservedSources & eventSourceWithoutClass) != 0;
     }
 
     private boolean canShareGenericTouchEvent() {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index c210e72..ab556b3 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2269,8 +2269,7 @@
                             mContext, shortcutType, userState.mUserId))
                     : userState.getShortcutTargetsLocked(shortcutType);
 
-            if (Flags.clearDefaultFromA11yShortcutTargetServiceRestore()
-                    && shortcutType == HARDWARE) {
+            if (shortcutType == HARDWARE) {
                 final String defaultService =
                         mContext.getString(R.string.config_defaultAccessibilityService);
                 final ComponentName defaultServiceComponent = TextUtils.isEmpty(defaultService)
@@ -3797,13 +3796,7 @@
                 || (Flags.enableMagnificationMultipleFingerMultipleTapGesture()
                     && userState.isMagnificationTwoFingerTripleTapEnabledLocked()));
 
-        final boolean createConnectionForCurrentCapability =
-                com.android.window.flags.Flags.alwaysDrawMagnificationFullscreenBorder()
-                        || (userState.getMagnificationCapabilitiesLocked()
-                                != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
-
-        final boolean connect = (shortcutEnabled && createConnectionForCurrentCapability)
-                || userHasMagnificationServicesLocked(userState);
+        final boolean connect = shortcutEnabled || userHasMagnificationServicesLocked(userState);
 
         getMagnificationConnectionManager().requestConnection(connect);
     }
@@ -4852,8 +4845,7 @@
 
         getMagnificationConnectionManager().setConnection(connection);
 
-        if (com.android.window.flags.Flags.alwaysDrawMagnificationFullscreenBorder()
-                && connection == null
+        if (connection == null
                 && mMagnificationController.isFullScreenMagnificationControllerInitialized()) {
             // Since the connection does not exist, the system ui cannot provide the border
             // implementation for fullscreen magnification. So we call reset to deactivate the
@@ -6548,8 +6540,7 @@
 
                 // Only continue setting up the packages if the service has been initialized.
                 // See: b/340927041
-                if (Flags.skipPackageChangeBeforeUserSwitch()
-                        && !mManagerService.isServiceInitializedLocked()) {
+                if (!mManagerService.isServiceInitializedLocked()) {
                     Slog.w(LOG_TAG,
                             "onSomePackagesChanged: service not initialized, skip the callback.");
                     return;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 9a81aa6..8b870db 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -434,21 +434,23 @@
         }
 
         /**
-         * Callbacks from window manager when there's an accessibility change in windows.
+         * Called when the windows for accessibility changed.
          *
-         * @param forceSend Send the windows for accessibility even if they haven't changed.
-         * @param topFocusedDisplayId The display Id which has the top focused window.
+         * @param forceSend             Send the windows for accessibility even if they haven't
+         *                              changed.
+         * @param topFocusedDisplayId   The display Id which has the top focused window.
          * @param topFocusedWindowToken The window token of top focused window.
-         * @param windows The windows for accessibility.
+         * @param screenSize            The size of the display that the change happened.
+         * @param accessibilityWindows  The windows for accessibility.
          */
         @Override
-        public void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId,
-                IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows) {
+        public void onAccessibilityWindowsChanged(boolean forceSend, int topFocusedDisplayId,
+                @NonNull IBinder topFocusedWindowToken, @NonNull Point screenSize,
+                @NonNull List<AccessibilityWindow> accessibilityWindows) {
             synchronized (mLock) {
-                if (!Flags.computeWindowChangesOnA11yV2()) {
-                    // If the flag is enabled, it's already done in #createWindowInfoListLocked.
-                    updateWindowsByWindowAttributesLocked(windows);
-                }
+                final List<WindowInfo> windows =
+                        createWindowInfoListLocked(screenSize, accessibilityWindows);
+
                 if (DEBUG) {
                     Slogf.i(LOG_TAG, "mDisplayId=%d, topFocusedDisplayId=%d, currentUserId=%d, "
                                     + "visibleBgUsers=%s", mDisplayId, topFocusedDisplayId,
@@ -463,14 +465,15 @@
                         Slogf.i(LOG_TAG, "%d windows changed: %s", windows.size(), windowsInfo);
                     }
                 }
-                if (shouldUpdateWindowsLocked(forceSend, windows)) {
+
+                if (forceSend || shouldUpdateWindowsLocked(windows)) {
                     mTopFocusedDisplayId = topFocusedDisplayId;
                     if (!isProxyed(topFocusedDisplayId)) {
                         mLastNonProxyTopFocusedDisplayId = topFocusedDisplayId;
                     }
                     mTopFocusedWindowToken = topFocusedWindowToken;
                     if (DEBUG) {
-                        Slogf.d(LOG_TAG, "onWindowsForAccessibilityChanged(): updating windows for "
+                        Slogf.d(LOG_TAG, "onAccessibilityWindowsChanged(): updating windows for "
                                         + "display %d and token %s",
                                 topFocusedDisplayId, topFocusedWindowToken);
                     }
@@ -480,39 +483,14 @@
                             windows);
                     // Someone may be waiting for the windows - advertise it.
                     mLock.notifyAll();
-                }
-                else if (DEBUG) {
-                    Slogf.d(LOG_TAG, "onWindowsForAccessibilityChanged(): NOT updating windows for "
+                } else if (DEBUG) {
+                    Slogf.d(LOG_TAG, "onAccessibilityWindowsChanged(): NOT updating windows for "
                                     + "display %d and token %s",
                             topFocusedDisplayId, topFocusedWindowToken);
                 }
             }
         }
 
-        /**
-         * Called when the windows for accessibility changed. This is called if
-         * {@link com.android.server.accessibility.Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2} is
-         * true.
-         *
-         * @param forceSend             Send the windows for accessibility even if they haven't
-         *                              changed.
-         * @param topFocusedDisplayId   The display Id which has the top focused window.
-         * @param topFocusedWindowToken The window token of top focused window.
-         * @param screenSize            The size of the display that the change happened.
-         * @param windows               The windows for accessibility.
-         */
-        @Override
-        public void onAccessibilityWindowsChanged(boolean forceSend, int topFocusedDisplayId,
-                @NonNull IBinder topFocusedWindowToken, @NonNull Point screenSize,
-                @NonNull List<AccessibilityWindow> windows) {
-            synchronized (mLock) {
-                final List<WindowInfo> windowInfoList =
-                        createWindowInfoListLocked(screenSize, windows);
-                onWindowsForAccessibilityChanged(forceSend, topFocusedDisplayId,
-                        topFocusedWindowToken, windowInfoList);
-            }
-        }
-
         private List<WindowInfo> createWindowInfoListLocked(@NonNull Point screenSize,
                 @NonNull List<AccessibilityWindow> visibleWindows) {
             final Set<IBinder> addedWindows = new ArraySet<>();
@@ -655,16 +633,6 @@
             return true;
         }
 
-        private void updateWindowsByWindowAttributesLocked(List<WindowInfo> windows) {
-            for (int i = windows.size() - 1; i >= 0; i--) {
-                final WindowInfo windowInfo = windows.get(i);
-                final IBinder token = windowInfo.token;
-                final int windowId = findWindowIdLocked(
-                        mAccessibilityUserManager.getCurrentUserIdLocked(), token);
-                updateWindowWithWindowAttributes(windowInfo, mWindowAttributes.get(windowId));
-            }
-        }
-
         private void updateWindowWithWindowAttributes(@NonNull WindowInfo windowInfo,
                 @Nullable AccessibilityWindowAttributes attributes) {
             if (attributes == null) {
@@ -674,12 +642,7 @@
             windowInfo.locales = attributes.getLocales();
         }
 
-        private boolean shouldUpdateWindowsLocked(boolean forceSend,
-                @NonNull List<WindowInfo> windows) {
-            if (forceSend) {
-                return true;
-            }
-
+        private boolean shouldUpdateWindowsLocked(@NonNull List<WindowInfo> windows) {
             final int windowCount = windows.size();
             if (VERBOSE) {
                 Slogf.v(LOG_TAG,
@@ -990,19 +953,6 @@
         private AccessibilityWindowInfo populateReportedWindowLocked(int userId,
                 WindowInfo window, SparseArray<AccessibilityWindowInfo> oldWindowsById) {
             final int windowId = findWindowIdLocked(userId, window.token);
-
-            // With the flag enabled, createWindowInfoListLocked() already removes invalid windows.
-            if (!Flags.computeWindowChangesOnA11yV2()) {
-                if (windowId < 0) {
-                    return null;
-                }
-
-                // Don't need to add the embedded hierarchy windows into the a11y windows list.
-                if (isEmbeddedHierarchyWindowsLocked(windowId)) {
-                    return null;
-                }
-            }
-
             final AccessibilityWindowInfo reportedWindow = AccessibilityWindowInfo.obtain();
 
             reportedWindow.setId(windowId);
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index 0ed239e..0cbbf6d 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -240,10 +240,7 @@
     }
 
     private void clear(MotionEvent event, int policyFlags) {
-        if (mState.isTouchExploring() || Flags.sendHoverEventsBasedOnEventStream()) {
-            // If a touch exploration gesture is in progress send events for its end.
-            sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
-        }
+        sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
         mDraggingPointerId = INVALID_POINTER_ID;
         // Send exit to any pointers that we have delivered as part of delegating or dragging.
         mDispatcher.sendUpForInjectedDownPointers(event, policyFlags);
@@ -562,10 +559,7 @@
         // clear any hover events that might have been queued and never sent.
         mSendHoverEnterAndMoveDelayed.clear();
         mSendHoverExitDelayed.cancel();
-        // If a touch exploration gesture is in progress send events for its end.
-        if (mState.isTouchExploring() || Flags.sendHoverEventsBasedOnEventStream()) {
-            sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
-        }
+        sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
         if (mState.isClear()) {
             if (!mSendHoverEnterAndMoveDelayed.isPending()) {
                 // Queue a delayed transition to STATE_TOUCH_EXPLORING.
@@ -1599,9 +1593,7 @@
             if (mEvents.size() == 0) {
                 return;
             }
-            if (Flags.sendHoverEventsBasedOnEventStream()) {
-                sendHoverExitAndTouchExplorationGestureEndIfNeeded(mPolicyFlags);
-            }
+            sendHoverExitAndTouchExplorationGestureEndIfNeeded(mPolicyFlags);
             // Send an accessibility event to announce the touch exploration start.
             mDispatcher.sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_START);
             if (isSendMotionEventsEnabled()) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index d3d80e1..11b8ccb 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -699,10 +699,9 @@
             if (!mRegistered) {
                 return false;
             }
-            // If the border implementation is on system ui side but the connection is not
+            // The border implementation is on system ui side but the connection is not
             // established, the fullscreen magnification should not work.
-            if (com.android.window.flags.Flags.alwaysDrawMagnificationFullscreenBorder()
-                    && !mMagnificationConnectionStateSupplier.get()) {
+            if (!mMagnificationConnectionStateSupplier.get()) {
                 return false;
             }
             if (DEBUG) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 51c4305..058b2be 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -51,7 +51,6 @@
 import com.android.server.LocalServices;
 import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.wm.WindowManagerInternal;
-import com.android.window.flags.Flags;
 
 import java.util.concurrent.Executor;
 
@@ -634,10 +633,8 @@
 
     @Override
     public void onFullScreenMagnificationActivationState(int displayId, boolean activated) {
-        if (Flags.alwaysDrawMagnificationFullscreenBorder()) {
-            getMagnificationConnectionManager()
-                    .onFullscreenMagnificationActivationChanged(displayId, activated);
-        }
+        getMagnificationConnectionManager()
+                .onFullscreenMagnificationActivationChanged(displayId, activated);
 
         if (activated) {
             synchronized (mLock) {
diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig
index 1803424..5d2ef77 100644
--- a/services/autofill/bugfixes.aconfig
+++ b/services/autofill/bugfixes.aconfig
@@ -44,6 +44,16 @@
 }
 
 flag {
+  name: "test_flag"
+  namespace: "autofill"
+  description: "Test flag "
+  bug: "377868687"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
   name: "add_session_id_to_client_state"
   namespace: "autofill"
   description: "Include the session id into the FillEventHistory events as part of ClientState"
diff --git a/services/autofill/features.aconfig b/services/autofill/features.aconfig
index b3fe5f2..5703633 100644
--- a/services/autofill/features.aconfig
+++ b/services/autofill/features.aconfig
@@ -31,9 +31,24 @@
 }
 
 flag {
+    name: "fill_dialog_improvements_impl"
+    is_exported: true
+    namespace: "autofill"
+    description: "Improvements for Fill Dialog for non-api changes"
+    bug: "336223371"
+}
+
+flag {
     name: "fill_dialog_improvements"
     is_exported: true
     namespace: "autofill"
     description: "Improvements for Fill Dialog, including deprecation of pre-trigger API's"
     bug: "336223371"
 }
+
+flag {
+  name: "add_last_focused_id_to_fill_event_history"
+  namespace: "autofill"
+  description: "Adds focused id to each event that's part of the fill event history"
+  bug: "334141398"
+}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index b52c6505..cd4ace2 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -900,13 +900,13 @@
      * Updates the last fill selection when an authentication was selected.
      */
     void setAuthenticationSelected(int sessionId, @Nullable Bundle clientState,
-            int uiType) {
+            int uiType, @Nullable AutofillId focusedId) {
         synchronized (mLock) {
             if (isValidEventLocked("setAuthenticationSelected()", sessionId)) {
                 mEventHistory.addEvent(
                         new Event(Event.TYPE_AUTHENTICATION_SELECTED, null, clientState, null, null,
                                 null, null, null, null, null, null,
-                                NO_SAVE_UI_REASON_NONE, uiType));
+                                NO_SAVE_UI_REASON_NONE, uiType, focusedId));
             }
         }
     }
@@ -915,13 +915,13 @@
      * Updates the last fill selection when an dataset authentication was selected.
      */
     void logDatasetAuthenticationSelected(@Nullable String selectedDataset, int sessionId,
-            @Nullable Bundle clientState, int uiType) {
+            @Nullable Bundle clientState, int uiType, @Nullable AutofillId focusedId) {
         synchronized (mLock) {
             if (isValidEventLocked("logDatasetAuthenticationSelected()", sessionId)) {
                 mEventHistory.addEvent(
                         new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset,
                                 clientState, null, null, null, null, null, null, null, null,
-                                NO_SAVE_UI_REASON_NONE, uiType));
+                                NO_SAVE_UI_REASON_NONE, uiType, focusedId));
             }
         }
     }
@@ -933,7 +933,7 @@
         synchronized (mLock) {
             if (isValidEventLocked("logSaveShown()", sessionId)) {
                 mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null, clientState, null,
-                        null, null, null, null, null, null, null));
+                        null, null, null, null, null, null, null, /* focusedId= */ null));
             }
         }
     }
@@ -942,13 +942,13 @@
      * Updates the last fill response when a dataset was selected.
      */
     void logDatasetSelected(@Nullable String selectedDataset, int sessionId,
-            @Nullable Bundle clientState,  int uiType) {
+            @Nullable Bundle clientState,  int uiType, @Nullable AutofillId focusedId) {
         synchronized (mLock) {
             if (isValidEventLocked("logDatasetSelected()", sessionId)) {
                 mEventHistory.addEvent(
                         new Event(Event.TYPE_DATASET_SELECTED, selectedDataset, clientState, null,
                                 null, null, null, null, null, null, null, NO_SAVE_UI_REASON_NONE,
-                                uiType));
+                                uiType, focusedId));
             }
         }
     }
@@ -956,13 +956,14 @@
     /**
      * Updates the last fill response when a dataset is shown.
      */
-    void logDatasetShown(int sessionId, @Nullable Bundle clientState, int uiType) {
+    void logDatasetShown(int sessionId, @Nullable Bundle clientState, int uiType,
+            @Nullable AutofillId focusedId) {
         synchronized (mLock) {
             if (isValidEventLocked("logDatasetShown", sessionId)) {
                 mEventHistory.addEvent(
                         new Event(Event.TYPE_DATASETS_SHOWN, null, clientState, null, null, null,
                                 null, null, null, null, null, NO_SAVE_UI_REASON_NONE,
-                                uiType));
+                                uiType, focusedId));
             }
         }
     }
@@ -970,7 +971,8 @@
     /**
      * Updates the last fill response when a view was entered.
      */
-    void logViewEntered(int sessionId, @Nullable Bundle clientState) {
+    void logViewEntered(int sessionId, @Nullable Bundle clientState,
+            @Nullable AutofillId focusedId) {
         synchronized (mLock) {
             if (!isValidEventLocked("logViewEntered", sessionId)) {
                 return;
@@ -988,7 +990,7 @@
 
             mEventHistory.addEvent(
                     new Event(Event.TYPE_VIEW_REQUESTED_AUTOFILL, null, clientState, null,
-                            null, null, null, null, null, null, null));
+                            null, null, null, null, null, null, null, focusedId));
         }
     }
 
@@ -1001,7 +1003,8 @@
             }
             mAugmentedAutofillEventHistory.addEvent(
                     new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset,
-                            clientState, null, null, null, null, null, null, null, null));
+                            clientState, null, null, null, null, null, null, null, null,
+                            /* focusedId= */ null));
         }
     }
 
@@ -1014,7 +1017,7 @@
             }
             mAugmentedAutofillEventHistory.addEvent(
                     new Event(Event.TYPE_DATASET_SELECTED, suggestionId, clientState, null, null,
-                            null, null, null, null, null, null));
+                            null, null, null, null, null, null, /* focusedId= */ null));
         }
     }
 
@@ -1029,7 +1032,7 @@
             mAugmentedAutofillEventHistory.addEvent(
                     new Event(Event.TYPE_DATASETS_SHOWN, null, clientState, null, null, null,
                             null, null, null, null, null, NO_SAVE_UI_REASON_NONE,
-                            UI_TYPE_INLINE));
+                            UI_TYPE_INLINE, /* focusedId= */ null));
 
         }
     }
@@ -1113,7 +1116,8 @@
                     clientState, selectedDatasets, ignoredDatasets,
                     changedFieldIds, changedDatasetIds,
                     manuallyFilledFieldIds, manuallyFilledDatasetIds,
-                    detectedFieldsIds, detectedFieldClassifications, saveDialogNotShowReason));
+                    detectedFieldsIds, detectedFieldClassifications, saveDialogNotShowReason,
+                    /* focusedId= */ null));
         }
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 8f12b1d..6b227d7 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -1871,7 +1871,7 @@
 
             if (mLogViewEntered) {
                 mLogViewEntered = false;
-                mService.logViewEntered(id, null);
+                mService.logViewEntered(id, null, mCurrentViewId);
             }
         }
 
@@ -2775,9 +2775,9 @@
                 forceRemoveFromServiceLocked();
                 return;
             }
+            mService.setAuthenticationSelected(id, mClientState, uiType, mCurrentViewId);
         }
 
-        mService.setAuthenticationSelected(id, mClientState, uiType);
 
         final int authenticationId = AutofillManager.makeAuthenticationId(requestId, datasetIndex);
         mHandler.sendMessage(
@@ -2850,7 +2850,7 @@
                 if (!mLoggedInlineDatasetShown) {
                     // Chip inflation already logged, do not log again.
                     // This is needed because every chip inflation will call this.
-                    mService.logDatasetShown(this.id, mClientState, uiType);
+                    mService.logDatasetShown(this.id, mClientState, uiType, mCurrentViewId);
                     Slog.d(TAG, "onShown(): " + uiType + ", " + numDatasetsShown);
                 }
                 mLoggedInlineDatasetShown = true;
@@ -2858,7 +2858,7 @@
                 mPresentationStatsEventLogger.logWhenDatasetShown(numDatasetsShown);
                 // Explicitly sets maybeSetSuggestionPresentedTimestampMs
                 mPresentationStatsEventLogger.maybeSetSuggestionPresentedTimestampMs();
-                mService.logDatasetShown(this.id, mClientState, uiType);
+                mService.logDatasetShown(this.id, mClientState, uiType, mCurrentViewId);
                 Slog.d(TAG, "onShown(): " + uiType + ", " + numDatasetsShown);
             }
         }
@@ -5139,7 +5139,7 @@
                         // so this calling logViewEntered will be a nop.
                         // Calling logViewEntered() twice will only log it once
                         // TODO(271181979): this is broken for multiple partitions
-                        mService.logViewEntered(this.id, null);
+                        mService.logViewEntered(this.id, null, mCurrentViewId);
                     }
 
                     // If this is the first time view is entered for inline, the last
@@ -6657,7 +6657,8 @@
             // Autofill it directly...
             if (dataset.getAuthentication() == null) {
                 if (generateEvent) {
-                    mService.logDatasetSelected(dataset.getId(), id, mClientState, uiType);
+                    mService.logDatasetSelected(dataset.getId(), id, mClientState, uiType,
+                            mCurrentViewId);
                 }
                 if (mCurrentViewId != null) {
                     mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
@@ -6667,7 +6668,8 @@
             }
 
             // ...or handle authentication.
-            mService.logDatasetAuthenticationSelected(dataset.getId(), id, mClientState, uiType);
+            mService.logDatasetAuthenticationSelected(dataset.getId(), id, mClientState, uiType,
+                        mCurrentViewId);
             mPresentationStatsEventLogger.maybeSetAuthenticationType(
                     AUTHENTICATION_TYPE_DATASET_AUTHENTICATION);
             // does not matter the value of isPrimary because null response won't be overridden.
diff --git a/services/backup/flags.aconfig b/services/backup/flags.aconfig
index fcb7934..28d3cae 100644
--- a/services/backup/flags.aconfig
+++ b/services/backup/flags.aconfig
@@ -69,3 +69,11 @@
     bug: "376661510"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "enable_read_all_external_storage_files"
+    is_exported: true
+    namespace: "onboarding"
+    description: "Enables read all external storage files"
+    bug: "376598575"
+}
\ No newline at end of file
diff --git a/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java b/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java
index 5e4bab15..02f1865 100644
--- a/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java
+++ b/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java
@@ -41,6 +41,7 @@
 import android.util.ArraySet;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
 import com.android.server.backup.internal.LifecycleOperationStorage;
@@ -71,8 +72,10 @@
     // Activity Manager; use this lock object to signal when a requested binding has
     // completed.
     private final Object mAgentConnectLock = new Object();
-    private IBackupAgent mConnectedAgent;
-    private volatile boolean mConnecting;
+    @GuardedBy("mAgentConnectLock")
+    @Nullable
+    private BackupAgentConnection mCurrentConnection;
+
     private final ArraySet<String> mRestoreNoRestrictedModePackages = new ArraySet<>();
     private final ArraySet<String> mBackupNoRestrictedModePackages = new ArraySet<>();
 
@@ -96,8 +99,18 @@
         mUserIdMsg = "[UserID:" + userId + "] ";
     }
 
+    private static final class BackupAgentConnection {
+        public final ApplicationInfo appInfo;
+        public IBackupAgent backupAgent;
+        public boolean connecting = true; // Assume we are trying to connect on creation.
+
+        private BackupAgentConnection(ApplicationInfo appInfo) {
+            this.appInfo = appInfo;
+        }
+    }
+
     /**
-     * Fires off a backup agent, blocking until it attaches (and ActivityManager will call
+     * Fires off a backup agent, blocking until it attaches (i.e. ActivityManager calls
      * {@link #agentConnected(String, IBinder)}) or until this operation times out.
      *
      * @param mode a {@code BACKUP_MODE} from {@link android.app.ApplicationThreadConstants}.
@@ -105,48 +118,56 @@
     @Nullable
     public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode,
             @BackupAnnotations.BackupDestination int backupDestination) {
-        IBackupAgent agent = null;
         synchronized (mAgentConnectLock) {
-            mConnecting = true;
-            mConnectedAgent = null;
             boolean useRestrictedMode = shouldUseRestrictedBackupModeForPackage(mode,
                     app.packageName);
+            if (mCurrentConnection != null) {
+                Slog.e(TAG, mUserIdMsg + "binding to new agent before unbinding from old one: "
+                        + mCurrentConnection.appInfo.packageName);
+            }
+            mCurrentConnection = new BackupAgentConnection(app);
+
+            // bindBackupAgent() is an async API. It will kick off the app's process and call
+            // agentConnected() when it receives the agent from the app.
+            boolean startedBindSuccessfully = false;
             try {
-                if (mActivityManager.bindBackupAgent(app.packageName, mode, mUserId,
-                        backupDestination, useRestrictedMode)) {
-                    Slog.d(TAG, mUserIdMsg + "awaiting agent for " + app);
-
-                    // success; wait for the agent to arrive
-                    // only wait 10 seconds for the bind to happen
-                    long timeoutMark = System.currentTimeMillis() + 10 * 1000;
-                    while (mConnecting && mConnectedAgent == null && (System.currentTimeMillis()
-                            < timeoutMark)) {
-                        try {
-                            mAgentConnectLock.wait(5000);
-                        } catch (InterruptedException e) {
-                            // just bail
-                            Slog.w(TAG, mUserIdMsg + "Interrupted: " + e);
-                            mConnecting = false;
-                            mConnectedAgent = null;
-                        }
-                    }
-
-                    // if we timed out with no connect, abort and move on
-                    if (mConnecting) {
-                        Slog.w(TAG, mUserIdMsg + "Timeout waiting for agent " + app);
-                        mConnectedAgent = null;
-                    }
-                    Slog.i(TAG, mUserIdMsg + "got agent " + mConnectedAgent);
-                    agent = mConnectedAgent;
-                }
+                startedBindSuccessfully = mActivityManager.bindBackupAgent(app.packageName, mode,
+                        mUserId, backupDestination, useRestrictedMode);
             } catch (RemoteException e) {
                 // can't happen - ActivityManager is local
             }
-        }
-        if (agent == null) {
+
+            if (!startedBindSuccessfully) {
+                Slog.w(TAG, mUserIdMsg + "bind request failed for " + app.packageName);
+                mCurrentConnection = null;
+            } else {
+                Slog.d(TAG, mUserIdMsg + "awaiting agent for " + app.packageName);
+
+                // Wait 10 seconds for the agent and then time out if we still haven't bound to it.
+                long timeoutMark = System.currentTimeMillis() + 10 * 1000;
+                while (mCurrentConnection != null && mCurrentConnection.connecting && (
+                        System.currentTimeMillis() < timeoutMark)) {
+                    try {
+                        mAgentConnectLock.wait(5000);
+                    } catch (InterruptedException e) {
+                        Slog.w(TAG, mUserIdMsg + "Interrupted: " + e);
+                        mCurrentConnection = null;
+                    }
+                }
+            }
+
+            if (mCurrentConnection != null) {
+                if (!mCurrentConnection.connecting) {
+                    return mCurrentConnection.backupAgent;
+                }
+                // If we are still connecting, we've timed out.
+                Slog.w(TAG, mUserIdMsg + "Timeout waiting for agent " + app);
+                mCurrentConnection = null;
+            }
+
             mActivityManagerInternal.clearPendingBackup(mUserId);
+            return null;
         }
-        return agent;
     }
 
     /**
@@ -154,30 +175,49 @@
      * It will tell the app to destroy the agent.
      */
     public void unbindAgent(ApplicationInfo app) {
-        try {
-            mActivityManager.unbindBackupAgent(app);
-        } catch (RemoteException e) {
-            // Can't happen - activity manager is local
+        synchronized (mAgentConnectLock) {
+            if (mCurrentConnection == null) {
+                Slog.w(TAG, mUserIdMsg + "unbindAgent but no current connection");
+            } else if (!mCurrentConnection.appInfo.packageName.equals(app.packageName)) {
+                Slog.w(TAG, mUserIdMsg + "unbindAgent for unexpected package: " + app.packageName
+                        + " expected: " + mCurrentConnection.appInfo.packageName);
+            } else {
+                mCurrentConnection = null;
+            }
+
+            // Even if we weren't expecting to be bound to this agent, we should still call
+            // ActivityManager just in case. It will ignore the call if it also wasn't expecting it.
+            try {
+                mActivityManager.unbindBackupAgent(app);
+            } catch (RemoteException e) {
+                // Can't happen - activity manager is local
+            }
         }
     }
 
     /**
      * Callback: a requested backup agent has been instantiated. This should only be called from
-     * the
-     * {@link ActivityManager} when it's telling us that an agent is ready after a call to
+     * the {@link ActivityManager} when it's telling us that an agent is ready after a call to
      * {@link #bindToAgentSynchronous(ApplicationInfo, int, int)}.
      */
     public void agentConnected(String packageName, IBinder agentBinder) {
         synchronized (mAgentConnectLock) {
-            if (getCallingUid() == android.os.Process.SYSTEM_UID) {
-                Slog.d(TAG,
-                        mUserIdMsg + "agentConnected pkg=" + packageName + " agent=" + agentBinder);
-                mConnectedAgent = IBackupAgent.Stub.asInterface(agentBinder);
-                mConnecting = false;
-            } else {
+            if (getCallingUid() != Process.SYSTEM_UID) {
                 Slog.w(TAG, mUserIdMsg + "Non-system process uid=" + getCallingUid()
                         + " claiming agent connected");
+                return;
             }
+
+            Slog.d(TAG, mUserIdMsg + "agentConnected pkg=" + packageName + " agent=" + agentBinder);
+            if (mCurrentConnection == null) {
+                Slog.w(TAG, mUserIdMsg + "was not expecting connection");
+            } else if (!mCurrentConnection.appInfo.packageName.equals(packageName)) {
+                Slog.w(TAG, mUserIdMsg + "got agent for unexpected package=" + packageName);
+            } else {
+                mCurrentConnection.backupAgent = IBackupAgent.Stub.asInterface(agentBinder);
+                mCurrentConnection.connecting = false;
+            }
+
             mAgentConnectLock.notifyAll();
         }
     }
@@ -189,16 +229,22 @@
      */
     public void agentDisconnected(String packageName) {
         synchronized (mAgentConnectLock) {
-            if (getCallingUid() == Process.SYSTEM_UID) {
-                mConnectedAgent = null;
-                mConnecting = false;
-            } else {
+            if (getCallingUid() != Process.SYSTEM_UID) {
                 Slog.w(TAG, mUserIdMsg + "Non-system process uid=" + getCallingUid()
                         + " claiming agent disconnected");
+                return;
             }
+
             Slog.w(TAG, mUserIdMsg + "agentDisconnected: the backup agent for " + packageName
                     + " died: cancel current operations");
 
+            // Only abort the current connection if the agent we were expecting or already
+            // connected to has disconnected.
+            if (mCurrentConnection != null && mCurrentConnection.appInfo.packageName.equals(
+                    packageName)) {
+                mCurrentConnection = null;
+            }
+
             // Offload operation cancellation off the main thread as the cancellation callbacks
             // might call out to BackupTransport. Other operations started on the same package
             // before the cancellation callback has executed will also be cancelled by the callback.
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 4b9065b..6069e34 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -88,6 +88,9 @@
         /** Called when a secure window shows on the virtual display. */
         void onSecureWindowShown(int displayId, @NonNull ActivityInfo activityInfo);
 
+        /** Called when a secure window is no longer shown on the virtual display. */
+        void onSecureWindowHidden(int displayId);
+
         /** Returns true when an intent should be intercepted */
         boolean shouldInterceptIntent(@NonNull Intent intent);
     }
@@ -123,6 +126,9 @@
     private boolean mIsMirrorDisplay = false;
     private final CountDownLatch mDisplayIdSetLatch = new CountDownLatch(1);
 
+    // Used for detecting changes in the window flags.
+    private int mCurrentWindowFlags = 0;
+
     @NonNull
     @GuardedBy("mGenericWindowPolicyControllerLock")
     private final ArraySet<Integer> mRunningUids = new ArraySet<>();
@@ -371,12 +377,19 @@
     public boolean keepActivityOnWindowFlagsChanged(ActivityInfo activityInfo, int windowFlags,
             int systemWindowFlags) {
         int displayId = waitAndGetDisplayId();
-        // The callback is fired only when windowFlags are changed. To let VirtualDevice owner
-        // aware that the virtual display has a secure window on top.
-        if ((windowFlags & FLAG_SECURE) != 0 && displayId != INVALID_DISPLAY) {
+        if (displayId != INVALID_DISPLAY) {
+            // The callback is fired only when windowFlags are changed. To let VirtualDevice owner
+            // aware that the virtual display has a secure window on top.
             // Post callback on the main thread, so it doesn't block activity launching.
-            mHandler.post(() -> mActivityListener.onSecureWindowShown(displayId, activityInfo));
+            if ((windowFlags & FLAG_SECURE) != 0 && (mCurrentWindowFlags & FLAG_SECURE) == 0) {
+                mHandler.post(
+                        () -> mActivityListener.onSecureWindowShown(displayId, activityInfo));
+            }
+            if ((windowFlags & FLAG_SECURE) == 0 && (mCurrentWindowFlags & FLAG_SECURE) != 0) {
+                mHandler.post(() -> mActivityListener.onSecureWindowHidden(displayId));
+            }
         }
+        mCurrentWindowFlags = windowFlags;
 
         if (!CompatChanges.isChangeEnabled(ALLOW_SECURE_ACTIVITY_DISPLAY_ON_REMOTE_DEVICE,
                 activityInfo.packageName,
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 8b5b93e..a1d621d 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -312,6 +312,17 @@
             }
         }
 
+        @Override
+        public void onSecureWindowHidden(int displayId) {
+            if (android.companion.virtualdevice.flags.Flags.activityControlApi()) {
+                try {
+                    mActivityListener.onSecureWindowHidden(displayId);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Unable to call mActivityListener for display: " + displayId, e);
+                }
+            }
+        }
+
         /**
          * Intercepts intent when matching any of the IntentFilter of any interceptor. Returns true
          * if the intent matches any filter notifying the DisplayPolicyController to abort the
diff --git a/services/core/Android.bp b/services/core/Android.bp
index aea16b0..6d60164 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -188,7 +188,7 @@
         "android.hardware.health-V1.0-java", // HIDL
         "android.hardware.health-V2.0-java", // HIDL
         "android.hardware.health-V2.1-java", // HIDL
-        "android.hardware.health-V3-java", // AIDL
+        "android.hardware.health-V4-java", // AIDL
         "android.hardware.health-translate-java",
         "android.hardware.light-V1-java",
         "android.hardware.security.authgraph-V1-java",
@@ -238,7 +238,6 @@
         "connectivity_flags_lib",
         "device_config_service_flags_java",
         "dreams_flags_lib",
-        "aconfig_flags_java",
         "aconfig_new_storage_flags_lib",
         "powerstats_flags_lib",
         "locksettings_flags_lib",
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 3dcca14..4cf17ae 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -69,6 +69,7 @@
 import android.sysprop.PowerProperties;
 import android.util.EventLog;
 import android.util.Slog;
+import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -303,6 +304,17 @@
      */
     @VisibleForTesting
     public long mLastBroadcastVoltageUpdateTime;
+    /**
+     * Time when the max charging current was updated last by HAL and we sent the
+     * {@link Intent#ACTION_BATTERY_CHANGED} broadcast.
+     * Note: This value is used to rate limit the {@link Intent#ACTION_BATTERY_CHANGED} broadcast
+     * so it is possible that max current was updated but we did not send the broadcast so in that
+     * case we do not update the time.
+     */
+    @VisibleForTesting
+    public long mLastBroadcastMaxChargingCurrentUpdateTime;
+
+    private boolean mIsFirstBatteryChangedUpdate = true;
 
     private Led mLed;
 
@@ -350,16 +362,21 @@
     private static final int ABSOLUTE_DECI_CELSIUS_DIFF_FOR_TEMP_UPDATE = 10;
     /**
      * This value is used to rate limit the {@link Intent#ACTION_BATTERY_CHANGED} broadcast. We
-     * only send the broadcast if the last voltage was updated at least 20s seconds back and has a
+     * only send the broadcast if the last voltage was updated at least 20 seconds back and has a
      * fluctuation of at least 1%.
      */
     private static final int TIME_DIFF_FOR_VOLTAGE_UPDATE_MS = 20000;
     /**
      * The value is used to rate limit the {@link Intent#ACTION_BATTERY_CHANGED} broadcast. We
-     * only send the broadcast if the last voltage was updated at least 20s seconds back and has a
+     * only send the broadcast if the last voltage was updated at least 20 seconds back and has a
      * fluctuation of at least 1%.
      */
     private static final float BASE_POINT_DIFF_FOR_VOLTAGE_UPDATE = 0.01f;
+    /**
+     * This value is used to rate limit the {@link Intent#ACTION_BATTERY_CHANGED} broadcast. We
+     * only send the broadcast if the last max charging current was updated at least 5 seconds back.
+     */
+    private static final int TIME_DIFF_FOR_MAX_CHARGING_CURRENT_UPDATE_MS = 5000;
 
     private final Handler.Callback mLocalCallback = msg -> {
         switch (msg.what) {
@@ -1252,8 +1269,10 @@
         if (!com.android.server.flags.Flags.rateLimitBatteryChangedBroadcast()) {
             return false;
         }
-        if (mLastBroadcastBatteryVoltage == 0 || mLastBroadcastBatteryTemperature == 0) {
+        if (mIsFirstBatteryChangedUpdate) {
             mLastBroadcastVoltageUpdateTime = SystemClock.elapsedRealtime();
+            mLastBroadcastMaxChargingCurrentUpdateTime = SystemClock.elapsedRealtime();
+            mIsFirstBatteryChangedUpdate = false;
             return false;
         }
 
@@ -1261,13 +1280,14 @@
                 mLastBroadcastBatteryVoltage != mHealthInfo.batteryVoltageMillivolts;
         final boolean temperatureUpdated =
                 mLastBroadcastBatteryTemperature != mHealthInfo.batteryTemperatureTenthsCelsius;
+        final boolean maxChargingCurrentUpdated =
+                mLastBroadcastMaxChargingCurrent != mHealthInfo.maxChargingCurrentMicroamps;
         final boolean otherStatesUpdated = forceUpdate
                 || mHealthInfo.batteryStatus != mLastBroadcastBatteryStatus
                 || mHealthInfo.batteryHealth != mLastBroadcastBatteryHealth
                 || mHealthInfo.batteryPresent != mLastBroadcastBatteryPresent
                 || mHealthInfo.batteryLevel != mLastBroadcastBatteryLevel
                 || mPlugType != mLastBroadcastPlugType
-                || mHealthInfo.maxChargingCurrentMicroamps != mLastBroadcastMaxChargingCurrent
                 || mHealthInfo.maxChargingVoltageMicrovolts != mLastBroadcastMaxChargingVoltage
                 || mInvalidCharger != mLastBroadcastInvalidCharger
                 || mHealthInfo.batteryCycleCount != mLastBroadcastBatteryCycleCount
@@ -1280,6 +1300,9 @@
             if (voltageUpdated) {
                 mLastBroadcastVoltageUpdateTime = SystemClock.elapsedRealtime();
             }
+            if (maxChargingCurrentUpdated) {
+                mLastBroadcastMaxChargingCurrentUpdateTime = SystemClock.elapsedRealtime();
+            }
             return false;
         }
 
@@ -1295,6 +1318,9 @@
                         >= TIME_DIFF_FOR_VOLTAGE_UPDATE_MS) {
             mLastBroadcastVoltageUpdateTime = SystemClock.elapsedRealtime();
 
+            if (maxChargingCurrentUpdated) {
+                mLastBroadcastMaxChargingCurrentUpdateTime = SystemClock.elapsedRealtime();
+            }
             return false;
         }
 
@@ -1307,6 +1333,20 @@
             if (voltageUpdated) {
                 mLastBroadcastVoltageUpdateTime = SystemClock.elapsedRealtime();
             }
+            if (maxChargingCurrentUpdated) {
+                mLastBroadcastMaxChargingCurrentUpdateTime = SystemClock.elapsedRealtime();
+            }
+            return false;
+        }
+
+        if (maxChargingCurrentUpdated
+                && SystemClock.elapsedRealtime() - mLastBroadcastMaxChargingCurrentUpdateTime
+                >= TIME_DIFF_FOR_MAX_CHARGING_CURRENT_UPDATE_MS) {
+            mLastBroadcastMaxChargingCurrentUpdateTime = SystemClock.elapsedRealtime();
+
+            if (voltageUpdated) {
+                mLastBroadcastVoltageUpdateTime = SystemClock.elapsedRealtime();
+            }
             return false;
         }
 
@@ -1615,6 +1655,9 @@
                 pw.println("  Wireless powered: " + mHealthInfo.chargerWirelessOnline);
                 pw.println("  Dock powered: " + mHealthInfo.chargerDockOnline);
                 pw.println("  Max charging current: " + mHealthInfo.maxChargingCurrentMicroamps);
+                pw.println(" Time when the latest updated value of the Max charging current was"
+                        + " sent via battery changed broadcast: "
+                        + TimeUtils.formatDuration(mLastBroadcastMaxChargingCurrentUpdateTime));
                 pw.println("  Max charging voltage: " + mHealthInfo.maxChargingVoltageMicrovolts);
                 pw.println("  Charge counter: " + mHealthInfo.batteryChargeCounterUah);
                 pw.println("  status: " + mHealthInfo.batteryStatus);
@@ -1624,7 +1667,8 @@
                 pw.println("  scale: " + BATTERY_SCALE);
                 pw.println("  voltage: " + mHealthInfo.batteryVoltageMillivolts);
                 pw.println(" Time when the latest updated value of the voltage was sent via "
-                        + "battery changed broadcast: " + mLastBroadcastVoltageUpdateTime);
+                        + "battery changed broadcast: "
+                        + TimeUtils.formatDuration(mLastBroadcastVoltageUpdateTime));
                 pw.println(" The last voltage value sent via the battery changed broadcast: "
                         + mLastBroadcastBatteryVoltage);
                 pw.println("  temperature: " + mHealthInfo.batteryTemperatureTenthsCelsius);
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 485bf31..36dff89 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -65,6 +65,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.IRemoteCallback;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
@@ -100,6 +101,9 @@
 import java.util.concurrent.Executors;
 import java.util.stream.Collectors;
 
+import com.android.server.pm.BackgroundInstallControlService;
+import com.android.server.pm.BackgroundInstallControlCallbackHelper;
+
 /**
  * @hide
  */
@@ -137,6 +141,10 @@
     static final int MBA_STATUS_NEW_INSTALL = 3;
     // used for indicating newly installed MBAs that are updated (but unused currently)
     static final int MBA_STATUS_UPDATED_NEW_INSTALL = 4;
+    // used for indicating preloaded MBAs that are downgraded
+    static final int MBA_STATUS_DOWNGRADED_PRELOADED = 5;
+    // used for indicating MBAs that are uninstalled
+    static final int MBA_STATUS_UNINSTALLED = 6;
 
     @VisibleForTesting
     static final String KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION =
@@ -201,7 +209,9 @@
          * @param mbaStatus Assign this value of MBA status to the returned elements.
          * @return a @{@code List<IBinaryTransparencyService.AppInfo>}
          */
-        private @NonNull List<IBinaryTransparencyService.AppInfo> collectAppInfo(
+        @VisibleForTesting
+        @NonNull
+        List<IBinaryTransparencyService.AppInfo> collectAppInfo(
                 PackageState packageState, int mbaStatus) {
             // compute content digest
             if (DEBUG) {
@@ -335,26 +345,28 @@
                         + " packages after considering APEXs.");
             }
 
-            // proceed with all preloaded apps
-            List<IBinaryTransparencyService.AppInfo> allUpdatedPreloadInfo =
-                    collectAllUpdatedPreloadInfo(packagesMeasured);
-            for (IBinaryTransparencyService.AppInfo appInfo : allUpdatedPreloadInfo) {
-                packagesMeasured.putBoolean(appInfo.packageName, true);
-                writeAppInfoToLog(appInfo);
-            }
-            if (DEBUG) {
-                Slog.d(TAG, "Measured " + packagesMeasured.size()
-                        + " packages after considering preloads");
-            }
-
-            if (CompatChanges.isChangeEnabled(LOG_MBA_INFO)) {
-                // lastly measure all newly installed MBAs
-                List<IBinaryTransparencyService.AppInfo> allMbaInfo =
-                        collectAllSilentInstalledMbaInfo(packagesMeasured);
-                for (IBinaryTransparencyService.AppInfo appInfo : allMbaInfo) {
+            if (!android.app.Flags.backgroundInstallControlCallbackApi()) {
+                // proceed with all preloaded apps
+                List<IBinaryTransparencyService.AppInfo> allUpdatedPreloadInfo =
+                        collectAllUpdatedPreloadInfo(packagesMeasured);
+                for (IBinaryTransparencyService.AppInfo appInfo : allUpdatedPreloadInfo) {
                     packagesMeasured.putBoolean(appInfo.packageName, true);
                     writeAppInfoToLog(appInfo);
                 }
+                if (DEBUG) {
+                    Slog.d(TAG, "Measured " + packagesMeasured.size()
+                            + " packages after considering preloads");
+                }
+
+                if (CompatChanges.isChangeEnabled(LOG_MBA_INFO)) {
+                    // lastly measure all newly installed MBAs
+                    List<IBinaryTransparencyService.AppInfo> allMbaInfo =
+                            collectAllSilentInstalledMbaInfo(packagesMeasured);
+                    for (IBinaryTransparencyService.AppInfo appInfo : allMbaInfo) {
+                        packagesMeasured.putBoolean(appInfo.packageName, true);
+                        writeAppInfoToLog(appInfo);
+                    }
+                }
             }
             long timeSpentMeasuring = System.currentTimeMillis() - currentTimeMs;
             digestAllPackagesLatency.logSample(timeSpentMeasuring);
@@ -464,7 +476,8 @@
                     apexInfo.signerDigests);
         }
 
-        private void writeAppInfoToLog(IBinaryTransparencyService.AppInfo appInfo) {
+        @VisibleForTesting
+        void writeAppInfoToLog(IBinaryTransparencyService.AppInfo appInfo) {
             // Must order by the proto's field number.
             FrameworkStatsLog.write(FrameworkStatsLog.MOBILE_BUNDLED_APP_INFO_GATHERED,
                     appInfo.packageName,
@@ -1158,6 +1171,94 @@
     }
 
     /**
+     * Receive callbacks from BIC to write silently installed apps to log
+     *
+     * TODO: Add a host test for testing registration and callback of BicCallbackHandler
+     *  b/380002484
+     */
+    @VisibleForTesting
+    static class BicCallbackHandler extends IRemoteCallback.Stub {
+        private static final String BIC_CALLBACK_HANDLER_TAG = TAG + ".BicCallbackHandler";
+
+        private static final int INSTALL_EVENT_TYPE_UNSET = -1;
+
+        private final IBicAppInfoHelper mBicAppInfoHelper;
+
+        @VisibleForTesting
+        BicCallbackHandler(IBicAppInfoHelper bicAppInfoHelper) {
+            mBicAppInfoHelper = bicAppInfoHelper;
+        }
+
+        @Override
+        public void sendResult(Bundle data) {
+            String packageName = data.getString(
+                    BackgroundInstallControlCallbackHelper.FLAGGED_PACKAGE_NAME_KEY);
+            int installType = data.getInt(
+                    BackgroundInstallControlCallbackHelper.INSTALL_EVENT_TYPE_KEY,
+                    INSTALL_EVENT_TYPE_UNSET);
+            if (packageName == null || installType == INSTALL_EVENT_TYPE_UNSET) {
+                Slog.w(BIC_CALLBACK_HANDLER_TAG, "Package name or install type is "
+                        + "unavailable, ignoring event");
+                return;
+            }
+            Slog.d(BIC_CALLBACK_HANDLER_TAG, "Detected new bic event for: " + packageName);
+            if (installType == BackgroundInstallControlService.INSTALL_EVENT_TYPE_INSTALL) {
+                PackageState packageState = LocalServices.getService(PackageManagerInternal.class)
+                    .getPackageStateInternal(packageName);
+                if (packageState == null) {
+                    Slog.w(TAG, "Package state is unavailable, ignoring the package "
+                            + packageName);
+                    return;
+                }
+                int mbaStatus = MBA_STATUS_NEW_INSTALL;
+                if (packageState.isUpdatedSystemApp()) {
+                    mbaStatus = MBA_STATUS_UPDATED_PRELOAD;
+                }
+                List<IBinaryTransparencyService.AppInfo> mbaInfo = mBicAppInfoHelper.collectAppInfo(
+                        packageState, mbaStatus);
+                for (IBinaryTransparencyService.AppInfo appInfo : mbaInfo) {
+                    mBicAppInfoHelper.writeAppInfoToLog(appInfo);
+                }
+            } else if (installType
+                        == BackgroundInstallControlService.INSTALL_EVENT_TYPE_UNINSTALL) {
+                IBinaryTransparencyService.AppInfo appInfo
+                    = new IBinaryTransparencyService.AppInfo();
+                // since app is already uninstalled we won't be able to retrieve additional
+                // info on it.
+                appInfo.packageName = packageName;
+                appInfo.mbaStatus = MBA_STATUS_UNINSTALLED;
+                mBicAppInfoHelper.writeAppInfoToLog(appInfo);
+            } else {
+                Slog.w(BIC_CALLBACK_HANDLER_TAG, "Unsupported BIC event: " + installType);
+            }
+        }
+
+        /**
+         * A wrapper of interface for{@link FrameworkStatsLog and ApkDigests}
+         * for easier testing
+         */
+        @VisibleForTesting
+        public interface IBicAppInfoHelper {
+
+            /**
+             * A wrapper of {@link FrameworkStatsLog}
+             *
+             * @param appInfo The app info of the changed MBA to be logged
+             */
+            public void writeAppInfoToLog(IBinaryTransparencyService.AppInfo appInfo);
+
+            /**
+             * A wrapper of {@link BinaryTransparencyServiceImpl}
+             *
+             * @param packageState The packageState provided retrieved from PackageManagerInternal
+             * @param mbaStatus The MBA status of the package
+             */
+            public List<IBinaryTransparencyService.AppInfo> collectAppInfo(
+                PackageState packageState, int mbaStatus);
+        }
+    };
+
+    /**
      * Called when the system service should publish a binder service using
      * {@link #publishBinderService(String, IBinder).}
      */
@@ -1534,6 +1635,43 @@
         }
     }
 
+    private void registerBicCallback() {
+        if(!com.android.server.flags.Flags.optionalBackgroundInstallControl()) {
+            Slog.d(TAG, "BICS is disabled for this device, skipping registration.");
+            return;
+        }
+        IBackgroundInstallControlService iBics =
+                IBackgroundInstallControlService.Stub.asInterface(
+                        ServiceManager.getService(
+                                Context.BACKGROUND_INSTALL_CONTROL_SERVICE));
+        if(iBics == null) {
+            Slog.e(TAG, "Failed to register BackgroundInstallControl callback, either "
+                + "background install control service does not exist or disabled on this "
+                + "build.");
+            return;
+        }
+        try {
+            iBics.registerBackgroundInstallCallback(
+                    new BicCallbackHandler(
+                        new BicCallbackHandler.IBicAppInfoHelper() {
+                            @Override
+                            public void writeAppInfoToLog(
+                                    IBinaryTransparencyService.AppInfo appInfo) {
+                                mServiceImpl.writeAppInfoToLog(appInfo);
+                            }
+
+                            @Override
+                            public List<IBinaryTransparencyService.AppInfo> collectAppInfo(
+                                PackageState packageState, int mbaStatus) {
+                                return mServiceImpl.collectAppInfo(packageState, mbaStatus);
+                            }
+                        }
+                    ));
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to register BackgroundInstallControl callback.");
+        }
+    }
+
     private boolean isPackagePreloaded(String packageName) {
         PackageManager pm = mContext.getPackageManager();
         try {
@@ -1575,8 +1713,12 @@
             }
 
             String packageName = data.getSchemeSpecificPart();
-            // now we've got to check what package is this
-            if (isPackagePreloaded(packageName) || isPackageAnApex(packageName)) {
+
+            boolean shouldMeasureMba =
+                !android.app.Flags.backgroundInstallControlCallbackApi()
+                && isPackagePreloaded(packageName);
+
+            if (shouldMeasureMba || isPackageAnApex(packageName)) {
                 Slog.d(TAG, packageName + " was updated. Scheduling measurement...");
                 UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext,
                         BinaryTransparencyService.this);
@@ -1596,6 +1738,10 @@
     private void registerAllPackageUpdateObservers() {
         registerApkAndNonStagedApexUpdateListener();
         registerStagedApexUpdateObserver();
+        if (android.app.Flags.backgroundInstallControlCallbackApi()
+                && CompatChanges.isChangeEnabled(LOG_MBA_INFO)) {
+            registerBicCallback();
+        }
     }
 
     private String translateContentDigestAlgorithmIdToString(int algorithmId) {
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index 99772c3..03d6c8b 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -1318,6 +1318,7 @@
                         }
                         XmlUtils.skipCurrentTag(parser);
                     } break;
+                    case "disabled-in-sku":
                     case "disabled-until-used-preinstalled-carrier-app": {
                         if (allowAppConfigs) {
                             String pkgname = parser.getAttributeValue(null, "package");
@@ -1334,6 +1335,24 @@
                         }
                         XmlUtils.skipCurrentTag(parser);
                     } break;
+                    case "enabled-in-sku-override": {
+                        if (allowAppConfigs) {
+                            String pkgname = parser.getAttributeValue(null, "package");
+                            if (pkgname == null) {
+                                Slog.w(TAG,
+                                        "<" + name + "> without "
+                                                + "package in " + permFile + " at "
+                                                + parser.getPositionDescription());
+                            } else if (!mDisabledUntilUsedPreinstalledCarrierApps.remove(pkgname)) {
+                                Slog.w(TAG,
+                                        "<" + name + "> packagename:" + pkgname + " not included"
+                                                + "in disabled-in-sku");
+                            }
+                        } else {
+                            logNotAllowedInPartition(name, permFile, parser);
+                        }
+                        XmlUtils.skipCurrentTag(parser);
+                    } break;
                     case "privapp-permissions": {
                         if (allowPrivappPermissions) {
                             // privapp permissions from system, apex, vendor, product and
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index ce66dc3..8da8358 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -176,6 +176,10 @@
                     "include-filter": "com.android.server.wm.BackgroundActivityStart*"
                 }
             ]
+        },
+        {
+            "name": "FrameworksMockingServicesTests_service_batteryServiceTest",
+            "file_patterns": ["BatteryService\\.java"]
         }
    ]
 }
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 2012f56..a45b715 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -55,6 +55,8 @@
 import android.net.vcn.VcnManager.VcnErrorCode;
 import android.net.vcn.VcnManager.VcnStatusCode;
 import android.net.vcn.VcnUnderlyingNetworkPolicy;
+import android.net.vcn.util.PersistableBundleUtils;
+import android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 import android.net.wifi.WifiInfo;
 import android.os.Binder;
 import android.os.Build;
@@ -90,8 +92,6 @@
 import com.android.server.vcn.Vcn;
 import com.android.server.vcn.VcnContext;
 import com.android.server.vcn.VcnNetworkProvider;
-import com.android.server.vcn.util.PersistableBundleUtils;
-import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import java.io.File;
 import java.io.FileDescriptor;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index ab3ab15..a58d850 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -5845,7 +5845,7 @@
             if (r.inSharedIsolatedProcess) {
                 app = mAm.mProcessList.getSharedIsolatedProcess(procName, r.appInfo.uid,
                         r.appInfo.packageName);
-                if (app != null) {
+                if (app != null && !app.isKilled()) {
                     final IApplicationThread thread = app.getThread();
                     final int pid = app.getPid();
                     final UidRecord uidRecord = app.getUidRecord();
@@ -5870,6 +5870,8 @@
                         // If a dead object exception was thrown -- fall through to
                         // restart the application.
                     }
+                } else {
+                    app = null;
                 }
             } else {
                 // If this service runs in an isolated process, then each time
@@ -9319,6 +9321,46 @@
             Slog.e(TAG, "stopForegroundServiceDelegateLocked delegate does not exist");
         }
     }
+    /**
+     * Handles notifications from MediaSessionService about active media service.
+     * This method evaluates the provided information and transitions corresponding service to
+     * foreground state.
+     *
+     * @param packageName The package name of the app running the service.
+     * @param userId The user ID associated with the service.
+     * @param notificationId The ID of the media notification associated with the service.
+     */
+    void notifyActiveMediaForegroundServiceLocked(@NonNull String packageName,
+            @UserIdInt int userId, int notificationId) {
+        if (!enableNotifyingActivityManagerWithMediaSessionStatusChange()) {
+            return;
+        }
+
+        final ServiceMap smap = mServiceMap.get(userId);
+        if (smap == null) {
+            return;
+        }
+        final int serviceSize = smap.mServicesByInstanceName.size();
+        for (int i = 0; i < serviceSize; i++) {
+            final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i);
+            if (sr.appInfo.packageName.equals(packageName) && !sr.isForeground) {
+                // foregroundServiceType is cleared when media session is user-disengaged
+                // and calls notifyInactiveMediaForegroundService->setServiceForegroundInnerLocked.
+                if (sr.foregroundServiceType
+                        == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE
+                        && sr.foregroundId == notificationId) {
+                    if (DEBUG_FOREGROUND_SERVICE) {
+                        Slog.d(TAG, "Moving media service to foreground for package "
+                                + packageName);
+                    }
+                    setServiceForegroundInnerLocked(sr, sr.foregroundId,
+                             sr.foregroundNoti, /* flags */ 0,
+                             ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK,
+                             /* callingUidStart */ 0);
+                }
+            }
+        }
+    }
 
     /**
      * Handles notifications from MediaSessionService about inactive media foreground services.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5c5361b..78dee31 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -131,6 +131,9 @@
 import static android.provider.Settings.Global.DEBUG_APP;
 import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
 import static android.security.Flags.preventIntentRedirect;
+import static android.security.Flags.preventIntentRedirectCollectNestedKeysOnServerIfNotCollected;
+import static android.security.Flags.preventIntentRedirectShowToastIfNestedKeysNotCollected;
+import static android.security.Flags.preventIntentRedirectThrowExceptionIfNestedKeysNotCollected;
 import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS;
 import static android.view.Display.INVALID_DISPLAY;
 
@@ -189,6 +192,7 @@
 
 import android.Manifest;
 import android.Manifest.permission;
+import android.annotation.EnforcePermission;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.PermissionMethod;
@@ -387,6 +391,7 @@
 import android.view.View;
 import android.view.WindowManager;
 import android.view.autofill.AutofillManagerInternal;
+import android.widget.Toast;
 
 import com.android.internal.annotations.CompositeRWLock;
 import com.android.internal.annotations.GuardedBy;
@@ -437,6 +442,7 @@
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
 import com.android.server.ThreadPriorityBooster;
+import com.android.server.UiThread;
 import com.android.server.Watchdog;
 import com.android.server.am.LowMemDetector.MemFactor;
 import com.android.server.appop.AppOpsService;
@@ -478,6 +484,7 @@
 
 import dalvik.annotation.optimization.NeverCompile;
 import dalvik.system.VMRuntime;
+
 import libcore.util.EmptyArray;
 
 import java.io.File;
@@ -17923,6 +17930,15 @@
         }
 
         @Override
+        public void notifyActiveMediaForegroundService(@NonNull String packageName,
+                @UserIdInt int userId, int notificationId) {
+            synchronized (ActivityManagerService.this) {
+                mServices.notifyActiveMediaForegroundServiceLocked(packageName, userId,
+                        notificationId);
+            }
+        }
+
+        @Override
         public void notifyInactiveMediaForegroundService(@NonNull String packageName,
                 @UserIdInt int userId, int notificationId) {
             synchronized (ActivityManagerService.this) {
@@ -19213,6 +19229,11 @@
             return mKeyFields.mCreatorPackage;
         }
 
+        @VisibleForTesting
+        public @NonNull Key getKeyFields() {
+            return mKeyFields;
+        }
+
         public static boolean isValid(@NonNull Intent intent) {
             IBinder binder = intent.getCreatorToken();
             IntentCreatorToken token = null;
@@ -19256,9 +19277,13 @@
                 this.mFlags = intent.getFlags() & Intent.IMMUTABLE_FLAGS;
                 ClipData clipData = intent.getClipData();
                 if (clipData != null) {
-                    this.mClipDataUris = new ArrayList<>(clipData.getItemCount());
-                    for (int i = 0; i < clipData.getItemCount(); i++) {
-                        this.mClipDataUris.add(clipData.getItemAt(i).getUri());
+                    clipData = clipData.cloneOnlyUriItems();
+                    if (clipData != null) {
+                        List<Uri> clipDataUris = new ArrayList<>();
+                        clipData.collectUris(clipDataUris);
+                        if (!clipDataUris.isEmpty()) {
+                            this.mClipDataUris = clipDataUris;
+                        }
                     }
                 }
             }
@@ -19304,9 +19329,32 @@
      */
     public void addCreatorToken(@Nullable Intent intent, String creatorPackage) {
         if (!preventIntentRedirect()) return;
-
         if (intent == null) return;
 
+        if ((intent.getExtendedFlags() & Intent.EXTENDED_FLAG_NESTED_INTENT_KEYS_COLLECTED) == 0) {
+            Slog.wtf(TAG,
+                    "[IntentRedirect] The intent does not have its nested keys collected as a "
+                            + "preparation for creating intent creator tokens. Intent: "
+                            + intent + "; creatorPackage: " + creatorPackage);
+            if (preventIntentRedirectShowToastIfNestedKeysNotCollected()) {
+                UiThread.getHandler().post(
+                        () -> Toast.makeText(mContext,
+                                "Nested keys not collected. go/report-bug-intentRedir to report a"
+                                        + " bug", Toast.LENGTH_LONG).show());
+            }
+            if (preventIntentRedirectThrowExceptionIfNestedKeysNotCollected()) {
+                // this flag will be internal only, not ramped to public.
+                throw new SecurityException(
+                        "The intent does not have its nested keys collected as a preparation for "
+                                + "creating intent creator tokens. Intent: "
+                                + intent + "; creatorPackage: " + creatorPackage);
+            }
+            if (preventIntentRedirectCollectNestedKeysOnServerIfNotCollected()) {
+                // this flag will be ramped to public.
+                intent.collectExtraIntentKeys();
+            }
+        }
+
         String targetPackage = intent.getComponent() != null
                 ? intent.getComponent().getPackageName()
                 : intent.getPackage();
@@ -19337,11 +19385,34 @@
             String creatorPackage) {
         if (IntentCreatorToken.isValid(intent)) return null;
         IntentCreatorToken.Key key = new IntentCreatorToken.Key(creatorUid, creatorPackage, intent);
+        return createOrGetIntentCreatorToken(intent, key);
+    }
+
+    /**
+     * @hide
+     */
+    @EnforcePermission("android.permission.INTERACT_ACROSS_USERS_FULL")
+    public IBinder refreshIntentCreatorToken(Intent intent) {
+        refreshIntentCreatorToken_enforcePermission();
+        IBinder binder = intent.getCreatorToken();
+        if (binder instanceof IntentCreatorToken) {
+            IntentCreatorToken token = (IntentCreatorToken) binder;
+            IntentCreatorToken.Key key = new IntentCreatorToken.Key(token.getCreatorUid(),
+                    token.getCreatorPackage(), intent);
+            return createOrGetIntentCreatorToken(intent, key);
+
+        } else {
+            throw new IllegalArgumentException("intent does not contain a creator token.");
+        }
+    }
+
+    private static IntentCreatorToken createOrGetIntentCreatorToken(Intent intent,
+            IntentCreatorToken.Key key) {
         IntentCreatorToken token;
         synchronized (sIntentCreatorTokenCache) {
             WeakReference<IntentCreatorToken> ref = sIntentCreatorTokenCache.get(key);
             if (ref == null || ref.get() == null) {
-                token = new IntentCreatorToken(creatorUid, creatorPackage, intent);
+                token = new IntentCreatorToken(key.mCreatorUid, key.mCreatorPackage, intent);
                 sIntentCreatorTokenCache.put(key, token.mRef);
             } else {
                 token = ref.get();
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index d3d3fc9..37d058b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -471,14 +471,14 @@
         }
         int userId = UserHandle.USER_CURRENT;
         final String cmd = getNextArgRequired();
-        if ("inactive".equals(cmd)) {
+        if ("inactive".equals(cmd) || "active".equals(cmd)) {
             String opt;
             while ((opt = getNextOption()) != null) {
                 if (opt.equals("--user")) {
                     userId = UserHandle.parseUserArg(getNextArgRequired());
                     if (userId == UserHandle.USER_ALL) {
                         err.println(
-                                "Error: Can't set media fgs inactive with user 'all'");
+                                "Error: Can't set media fgs with user 'all'");
                         return -1;
                     }
                 } else {
@@ -492,8 +492,13 @@
                 err.println("Error: notification id cannot be zero");
                 return -1;
             }
-            mInternal.mInternal.notifyInactiveMediaForegroundService(pkgName,
-                    userId, notificationId);
+            if ("inactive".equals(cmd)) {
+                mInternal.mInternal.notifyInactiveMediaForegroundService(pkgName,
+                        userId, notificationId);
+            } else {
+                mInternal.mInternal.notifyActiveMediaForegroundService(pkgName,
+                        userId, notificationId);
+            }
             return 0;
         }
         err.println("Error: Unknown set-media-foreground-service command: " + cmd);
@@ -852,6 +857,7 @@
                 }
                 options.setDismissKeyguardIfInsecure();
             }
+            intent.collectExtraIntentKeys();
             if (mWaitOption) {
                 result = mInternal.startActivityAndWait(null, SHELL_PACKAGE_NAME, null, intent,
                         mimeType, null, null, 0, mStartFlags, profilerInfo,
@@ -970,6 +976,7 @@
         }
         pw.println("Starting service: " + intent);
         pw.flush();
+        intent.collectExtraIntentKeys();
         ComponentName cn = mInterface.startService(null, intent, intent.getType(),
                 asForeground, SHELL_PACKAGE_NAME, null, mUserId);
         if (cn == null) {
@@ -1002,6 +1009,7 @@
         }
         pw.println("Stopping service: " + intent);
         pw.flush();
+        intent.collectExtraIntentKeys();
         int result = mInterface.stopService(null, intent, intent.getType(), mUserId);
         if (result == 0) {
             err.println("Service not stopped: was not running.");
@@ -1399,6 +1407,12 @@
             heapFile = "/data/local/tmp/heapdump-" + logNameTimeString + ".prof";
         }
 
+        String argAfterHeapFile = getNextArg();
+        if (argAfterHeapFile != null) {
+            err.println("Error: Arguments cannot be placed after the heap file");
+            return -1;
+        }
+
         // Writes an error message to stderr on failure
         ParcelFileDescriptor fd = openFileForSystem(heapFile, "w");
         if (fd == null) {
@@ -4683,9 +4697,9 @@
             pw.println("         --protobuf: format output using protobuffer");
             pw.println("  set-app-zygote-preload-timeout <TIMEOUT_IN_MS>");
             pw.println("         Set the timeout for preloading code in the app-zygote");
-            pw.println("  set-media-foreground-service inactive [--user USER_ID]"
-                    + " <PACKAGE> <NOTIFICATION_ID>");
-            pw.println("         Set an app's media foreground service inactive.");
+            pw.println("  set-media-foreground-service inactive|active [--user USER_ID] <PACKAGE>"
+                            + " <NOTIFICATION_ID>");
+            pw.println("         Set an app's media service inactive or active.");
             Intent.printIntentArgsHelp(pw, "");
         }
     }
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 415f78a..b7a5f3e 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -598,7 +598,7 @@
         }
 
         if (r != null) {
-            mPackageWatchdog.onPackageFailure(r.getPackageListWithVersionCode(),
+            mPackageWatchdog.notifyPackageFailure(r.getPackageListWithVersionCode(),
                     PackageWatchdog.FAILURE_REASON_APP_CRASH);
 
             synchronized (mService) {
@@ -1142,7 +1142,7 @@
         }
         // Notify PackageWatchdog without the lock held
         if (packageList != null) {
-            mPackageWatchdog.onPackageFailure(packageList,
+            mPackageWatchdog.notifyPackageFailure(packageList,
                     PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING);
         }
     }
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 2eb9f3c..400ebfd 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1126,20 +1126,8 @@
                     break;
                 }
                 case FrameworkStatsLog.BATTERY_USAGE_STATS_SINCE_RESET_USING_POWER_PROFILE_MODEL:
-                    if (Flags.disableCompositeBatteryUsageStatsAtoms()) {
-                        return StatsManager.PULL_SKIP;
-                    }
+                    return StatsManager.PULL_SKIP;
 
-                    final BatteryUsageStatsQuery queryPowerProfile =
-                            new BatteryUsageStatsQuery.Builder()
-                                    .setMaxStatsAgeMs(0)
-                                    .includeProcessStateData()
-                                    .includeVirtualUids()
-                                    .powerProfileModeledOnly()
-                                    .includePowerModels()
-                                    .build();
-                    bus = getBatteryUsageStats(List.of(queryPowerProfile)).get(0);
-                    break;
                 case FrameworkStatsLog.BATTERY_USAGE_STATS_BEFORE_RESET: {
                     if (Flags.disableCompositeBatteryUsageStatsAtoms()) {
                         return StatsManager.PULL_SKIP;
@@ -1262,6 +1250,17 @@
             mFrameworkStatsLogger = frameworkStatsLogger;
         }
 
+        private static float clampPowerMah(double powerMah, String consumer) {
+            float resultPowerMah = 0;
+            if (powerMah <= Float.MAX_VALUE && powerMah >= Float.MIN_VALUE) {
+                resultPowerMah = (float) powerMah;
+            } else {
+                // Handle overflow appropriately
+                Slog.wtfStack(TAG, consumer + " reported powerMah float overflow: " + powerMah);
+            }
+            return resultPowerMah;
+        }
+
         /**
          * Generates StatsEvents for the supplied battery usage stats and adds them to
          * the supplied list.
@@ -1282,7 +1281,8 @@
                     bus.getAggregateBatteryConsumer(
                             BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
 
-            final float totalDeviceConsumedPowerMah = (float) deviceConsumer.getConsumedPower();
+            final float totalDeviceConsumedPowerMah =
+                    clampPowerMah(deviceConsumer.getConsumedPower(), "AggregateBatteryConsumer");
 
             for (@BatteryConsumer.PowerComponentId int powerComponentId :
                     deviceConsumer.getPowerComponentIds()) {
@@ -1314,7 +1314,9 @@
             // Log single atom for BatteryUsageStats per uid/process_state/component/etc.
             for (UidBatteryConsumer uidConsumer : uidConsumers) {
                 final int uid = uidConsumer.getUid();
-                final float totalConsumedPowerMah = (float) uidConsumer.getConsumedPower();
+
+                final float totalConsumedPowerMah =
+                        clampPowerMah(uidConsumer.getConsumedPower(), "uidConsumer-" + uid);
 
                 for (@BatteryConsumer.PowerComponentId int powerComponentId :
                         uidConsumer.getPowerComponentIds()) {
@@ -1358,7 +1360,10 @@
             }
 
             final String powerComponentName = batteryConsumer.getPowerComponentName(componentId);
-            final float powerMah = (float) batteryConsumer.getConsumedPower(key);
+            final double consumedPowerMah = batteryConsumer.getConsumedPower(key);
+            float powerMah =
+                    clampPowerMah(
+                            consumedPowerMah, "uidConsumer-" + uid + "-" + powerComponentName);
             final long powerComponentDurationMillis = batteryConsumer.getUsageDurationMillis(key);
 
             if (powerMah == 0 && powerComponentDurationMillis == 0) {
@@ -3167,7 +3172,7 @@
         }
     }
 
-    private void dumpUsageStats(FileDescriptor fd, PrintWriter pw, int model,
+    private void dumpUsageStats(FileDescriptor fd, PrintWriter pw,
             boolean proto, boolean accumulated) {
         awaitCompletion();
         syncStats("dump", BatteryExternalStatsWorker.UPDATE_ALL);
@@ -3179,9 +3184,6 @@
         if (Flags.batteryUsageStatsByPowerAndScreenState()) {
             builder.includeScreenStateData().includePowerStateData();
         }
-        if (model == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
-            builder.powerProfileModeledOnly();
-        }
         if (accumulated) {
             builder.accumulated();
         }
@@ -3376,7 +3378,6 @@
                     dumpPowerProfile(pw);
                     return;
                 } else if ("--usage".equals(arg)) {
-                    int model = BatteryConsumer.POWER_MODEL_UNDEFINED;
                     boolean proto = false;
                     boolean accumulated = false;
                     for (int j = i + 1; j < args.length; j++) {
@@ -3384,29 +3385,12 @@
                             case "--proto":
                                 proto = true;
                                 break;
-                            case "--model": {
-                                if (j + 1 < args.length) {
-                                    j++;
-                                    if ("power-profile".equals(args[j])) {
-                                        model = BatteryConsumer.POWER_MODEL_POWER_PROFILE;
-                                    } else {
-                                        pw.println("Unknown power model: " + args[j]);
-                                        dumpHelp(pw);
-                                        return;
-                                    }
-                                } else {
-                                    pw.println("--model without a value");
-                                    dumpHelp(pw);
-                                    return;
-                                }
-                                break;
-                            }
                             case "--accumulated":
                                 accumulated = true;
                                 break;
                         }
                     }
-                    dumpUsageStats(fd, pw, model, proto, accumulated);
+                    dumpUsageStats(fd, pw, proto, accumulated);
                     return;
                 } else if ("--wakeups".equals(arg)) {
                     mCpuWakeupStats.dump(new IndentingPrintWriter(pw, "  "),
diff --git a/services/core/java/com/android/server/am/BroadcastController.java b/services/core/java/com/android/server/am/BroadcastController.java
index c6cb67f..354f281 100644
--- a/services/core/java/com/android/server/am/BroadcastController.java
+++ b/services/core/java/com/android/server/am/BroadcastController.java
@@ -57,6 +57,7 @@
 import android.app.ApplicationThreadConstants;
 import android.app.BackgroundStartPrivileges;
 import android.app.BroadcastOptions;
+import android.app.BroadcastStickyCache;
 import android.app.IApplicationThread;
 import android.app.compat.CompatChanges;
 import android.appwidget.AppWidgetManager;
@@ -183,6 +184,13 @@
     final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();
 
     /**
+     * If {@code false} invalidate the list of {@link android.os.IpcDataCache} present inside the
+     * {@link BroadcastStickyCache} class.
+     * The invalidation is required to start caching of the sticky broadcast in the client side.
+     */
+    private volatile boolean mAreStickyCachesInvalidated = false;
+
+    /**
      * Resolver for broadcast intents to registered receivers.
      * Holds BroadcastFilter (subclass of IntentFilter).
      */
@@ -288,6 +296,11 @@
             IIntentReceiver receiver, IntentFilter filter, String permission,
             int userId, int flags) {
         mService.enforceNotIsolatedCaller("registerReceiver");
+
+        if (!mAreStickyCachesInvalidated) {
+            BroadcastStickyCache.invalidateAllCaches();
+            mAreStickyCachesInvalidated = true;
+        }
         ArrayList<StickyBroadcast> stickyBroadcasts = null;
         ProcessRecord callerApp = null;
         final boolean visibleToInstantApps =
@@ -700,6 +713,7 @@
             String[] excludedPackages, int appOp, Bundle bOptions,
             boolean serialized, boolean sticky, int userId) {
         mService.enforceNotIsolatedCaller("broadcastIntent");
+        final int result;
 
         synchronized (mService) {
             intent = verifyBroadcastLocked(intent);
@@ -722,7 +736,7 @@
 
             final long origId = Binder.clearCallingIdentity();
             try {
-                return broadcastIntentLocked(callerApp,
+                result = broadcastIntentLocked(callerApp,
                         callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
                         intent, resolvedType, resultToApp, resultTo, resultCode, resultData,
                         resultExtras, requiredPermissions, excludedPermissions, excludedPackages,
@@ -733,6 +747,11 @@
                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
+
+        if (sticky && result == ActivityManager.BROADCAST_SUCCESS) {
+            BroadcastStickyCache.invalidateCache(intent.getAction());
+        }
+        return result;
     }
 
     // Not the binder call surface
@@ -743,6 +762,7 @@
             boolean serialized, boolean sticky, int userId,
             BackgroundStartPrivileges backgroundStartPrivileges,
             @Nullable int[] broadcastAllowList) {
+        final int result;
         synchronized (mService) {
             intent = verifyBroadcastLocked(intent);
 
@@ -750,7 +770,7 @@
             String[] requiredPermissions = requiredPermission == null ? null
                     : new String[] {requiredPermission};
             try {
-                return broadcastIntentLocked(null, packageName, featureId, intent, resolvedType,
+                result =  broadcastIntentLocked(null, packageName, featureId, intent, resolvedType,
                         resultToApp, resultTo, resultCode, resultData, resultExtras,
                         requiredPermissions, null, null, OP_NONE, bOptions, serialized, sticky, -1,
                         uid, realCallingUid, realCallingPid, userId,
@@ -760,6 +780,11 @@
                 Binder.restoreCallingIdentity(origId);
             }
         }
+
+        if (sticky && result == ActivityManager.BROADCAST_SUCCESS) {
+            BroadcastStickyCache.invalidateCache(intent.getAction());
+        }
+        return result;
     }
 
     @GuardedBy("mService")
@@ -1458,6 +1483,7 @@
                     list.add(StickyBroadcast.create(new Intent(intent), deferUntilActive,
                             callingUid, callerAppProcessState, resolvedType));
                 }
+                BroadcastStickyCache.invalidateCache(intent.getAction());
             }
         }
 
@@ -1724,6 +1750,7 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
+        final ArrayList<String> changedStickyBroadcasts = new ArrayList<>();
         synchronized (mStickyBroadcasts) {
             ArrayMap<String, ArrayList<StickyBroadcast>> stickies = mStickyBroadcasts.get(userId);
             if (stickies != null) {
@@ -1740,12 +1767,16 @@
                     if (list.size() <= 0) {
                         stickies.remove(intent.getAction());
                     }
+                    changedStickyBroadcasts.add(intent.getAction());
                 }
                 if (stickies.size() <= 0) {
                     mStickyBroadcasts.remove(userId);
                 }
             }
         }
+        for (int i = changedStickyBroadcasts.size() - 1; i >= 0; --i) {
+            BroadcastStickyCache.invalidateCache(changedStickyBroadcasts.get(i));
+        }
     }
 
     void finishReceiver(IBinder caller, int resultCode, String resultData,
@@ -2124,9 +2155,18 @@
     }
 
     void removeStickyBroadcasts(int userId) {
+        final ArrayList<String> changedStickyBroadcasts = new ArrayList<>();
         synchronized (mStickyBroadcasts) {
+            final ArrayMap<String, ArrayList<StickyBroadcast>> stickies =
+                    mStickyBroadcasts.get(userId);
+            if (stickies != null) {
+                changedStickyBroadcasts.addAll(stickies.keySet());
+            }
             mStickyBroadcasts.remove(userId);
         }
+        for (int i = changedStickyBroadcasts.size() - 1; i >= 0; --i) {
+            BroadcastStickyCache.invalidateCache(changedStickyBroadcasts.get(i));
+        }
     }
 
     @NeverCompile
diff --git a/services/core/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java
index a32d3cb..05aeb42 100644
--- a/services/core/java/com/android/server/am/BroadcastFilter.java
+++ b/services/core/java/com/android/server/am/BroadcastFilter.java
@@ -57,7 +57,6 @@
     final boolean visibleToInstantApp;
     public final boolean exported;
     final int initialPriority;
-    final ApplicationInfo applicationInfo;
 
     BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList,
             String _packageName, String _featureId, String _receiverId, String _requiredPermission,
@@ -74,10 +73,9 @@
         instantApp = _instantApp;
         visibleToInstantApp = _visibleToInstantApp;
         exported = _exported;
-        applicationInfo = _applicationInfo;
         initialPriority = getPriority();
         setPriority(calculateAdjustedPriority(owningUid, initialPriority,
-                applicationInfo, platformCompat));
+                _applicationInfo, platformCompat));
     }
 
     public @Nullable String getReceiverClassName() {
@@ -91,7 +89,7 @@
     }
 
     public @NonNull ApplicationInfo getApplicationInfo() {
-        return applicationInfo;
+        return receiverList.app.info;
     }
 
     @NeverCompile
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index da5b1fd..2f5362f 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -2122,7 +2122,7 @@
                     Slog.d(TAG_AM,
                             "Performing native compaction for pid=" + pid
                                     + " type=" + compactProfile.name());
-                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "compactSystem");
+                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "compactNative");
                     try {
                         mProcessDependencies.performCompaction(compactProfile, pid);
                     } catch (Exception e) {
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index ab7cd5f..1a6051b 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -66,6 +66,9 @@
 # Activity Security
 per-file ActivityManager* = file:/ACTIVITY_SECURITY_OWNERS
 
+# Aconfig Flags
+per-file flags.aconfig = yamasani@google.com, bills@google.com, nalini@google.com
+
 # Londoners
 michaelwr@google.com #{LAST_RESORT_SUGGESTION}
 narayan@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index b84bf6b9..f42641e 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1376,9 +1376,11 @@
             ProcessRecord app = lruList.get(i);
             final ProcessStateRecord state = app.mState;
             if (!app.isKilledByAm() && app.getThread() != null) {
-                // We don't need to apply the update for the process which didn't get computed
-                if (state.getCompletedAdjSeq() == mAdjSeq) {
-                    applyOomAdjLSP(app, doingAll, now, nowElapsed, oomAdjReason, true);
+                if (!Flags.fixApplyOomadjOrder()) {
+                    // We don't need to apply the update for the process which didn't get computed
+                    if (state.getCompletedAdjSeq() == mAdjSeq) {
+                        applyOomAdjLSP(app, doingAll, now, nowElapsed, oomAdjReason, true);
+                    }
                 }
 
                 if (app.isPendingFinishAttach()) {
@@ -1480,6 +1482,19 @@
             }
         }
 
+        if (Flags.fixApplyOomadjOrder()) {
+            // We need to apply the update starting from the least recently used.
+            // Otherwise, they won't be in the correct LRU order in LMKD.
+            for (int i = 0; i < numLru; i++) {
+                ProcessRecord app = lruList.get(i);
+                // We don't need to apply the update for the process which didn't get computed
+                if (!app.isKilledByAm() && app.getThread() != null
+                        && app.mState.getCompletedAdjSeq() == mAdjSeq) {
+                    applyOomAdjLSP(app, doingAll, now, nowElapsed, oomAdjReason, true);
+                }
+            }
+        }
+
         if (!mProcsToOomAdj.isEmpty()) {
             mInjector.batchSetOomAdj(mProcsToOomAdj);
             mProcsToOomAdj.clear();
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 78c4f74..e838a8d 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -42,7 +42,6 @@
 import static com.android.aconfig_new_storage.Flags.enableAconfigStorageDaemon;
 import static com.android.aconfig_new_storage.Flags.supportImmediateLocalOverrides;
 import static com.android.aconfig_new_storage.Flags.supportClearLocalOverridesImmediately;
-import static com.android.aconfig.flags.Flags.enableSystemAconfigdRust;
 
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
@@ -140,6 +139,8 @@
     // The list is sorted.
     @VisibleForTesting
     static final String[] sDeviceConfigAconfigScopes = new String[] {
+        "aaos_audio_triage",
+        "aaos_power_triage",
         "aaos_sdv",
         "accessibility",
         "android_core_networking",
@@ -459,9 +460,8 @@
     static ProtoInputStream sendAconfigdRequests(ProtoOutputStream requests) {
         // connect to aconfigd socket
         LocalSocket client = new LocalSocket();
-        String socketName = enableSystemAconfigdRust()
-                    ? "aconfigd_system" : "aconfigd";
-        try{
+        String socketName = "aconfigd_system";
+        try {
             client.connect(new LocalSocketAddress(
                 socketName, LocalSocketAddress.Namespace.RESERVED));
             Slog.d(TAG, "connected to aconfigd socket");
@@ -533,9 +533,8 @@
      * @param packageName the package of the flag
      * @param flagName the name of the flag
      * @param immediate if true, clear immediately; otherwise, clear on next reboot
-     *
-     * @hide
      */
+    @VisibleForTesting
     public static void writeFlagOverrideRemovalRequest(
         ProtoOutputStream proto, String packageName, String flagName, boolean immediate) {
       long msgsToken = proto.start(StorageRequestMessages.MSGS);
@@ -591,7 +590,8 @@
      * apply flag local override in aconfig new storage
      * @param props
      */
-    static void setLocalOverridesInNewStorage(DeviceConfig.Properties props) {
+    @VisibleForTesting
+    public static void setLocalOverridesInNewStorage(DeviceConfig.Properties props) {
         int num_requests = 0;
         ProtoOutputStream requests = new ProtoOutputStream();
         for (String flagName : props.getKeyset()) {
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 6d247d2..89e4a8d 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -245,6 +245,14 @@
 }
 
 flag {
+    name: "fix_apply_oomadj_order"
+    namespace: "backstage_power"
+    is_fixed_read_only: true
+    description: "Fix the iteration direction of process LRU list when applying oom adj"
+    bug: "378580264"
+}
+
+flag {
     name: "phantom_processes_fix"
     namespace: "backstage_power"
     description: "Make sure setProcessGroupForPhantomProcessOfApp deals with phantom processes properly"
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 8c5152f..6f8dc10 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -100,6 +100,7 @@
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
 import com.android.server.SystemService.TargetUser;
+import com.android.server.utils.LazyJniRegistrar;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.CompatScaleProvider;
 
@@ -158,6 +159,10 @@
     private static final String GAME_MODE_INTERVENTION_LIST_FILE_NAME =
             "game_mode_intervention.list";
 
+    static {
+        LazyJniRegistrar.registerGameManagerService();
+    }
+
     private final Context mContext;
     private final Object mLock = new Object();
     private final Object mDeviceConfigLock = new Object();
diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
index ed41f2e..fa2e674 100644
--- a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
+++ b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
@@ -31,7 +31,6 @@
 import static android.app.AppOpsManager.OP_NONE;
 import static android.app.AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO;
 import static android.app.AppOpsManager.OP_RECORD_AUDIO;
-import static android.app.AppOpsManager.OP_TAKE_AUDIO_FOCUS;
 import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
 import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
 import static android.app.AppOpsManager.UID_STATE_NONEXISTENT;
@@ -177,8 +176,6 @@
             case OP_RECORD_AUDIO:
             case OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO:
                 return PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
-            case OP_TAKE_AUDIO_FOCUS:
-                return PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL;
             default:
                 return PROCESS_CAPABILITY_NONE;
         }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 40d5f86..c6317bd 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -4954,22 +4954,24 @@
         }
 
         final Set<Integer> deviceTypes = getDeviceSetForStreamDirect(streamType);
-        final Set<Integer> absVolumeMultiModeCaseDevices =
-                AudioSystem.intersectionAudioDeviceTypes(
-                        mAbsVolumeMultiModeCaseDevices, deviceTypes);
-        if (absVolumeMultiModeCaseDevices.isEmpty()) {
+        Set<Integer> absVolumeDeviceTypes = new ArraySet<>(
+                AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
+        absVolumeDeviceTypes.addAll(mAbsVolumeMultiModeCaseDevices);
+
+        final Set<Integer> absVolumeDevices =
+                AudioSystem.intersectionAudioDeviceTypes(absVolumeDeviceTypes, deviceTypes);
+        if (absVolumeDevices.isEmpty()) {
             return;
         }
-        if (absVolumeMultiModeCaseDevices.size() > 1) {
+        if (absVolumeDevices.size() > 1) {
             Log.w(TAG, "onUpdateContextualVolumes too many active devices: "
-                    + absVolumeMultiModeCaseDevices.stream().map(AudioSystem::getOutputDeviceName)
+                    + absVolumeDevices.stream().map(AudioSystem::getOutputDeviceName)
                         .collect(Collectors.joining(","))
                     + ", for stream: " + streamType);
             return;
         }
 
-        final int device = absVolumeMultiModeCaseDevices.toArray(new Integer[0])[0].intValue();
-
+        final int device = absVolumeDevices.toArray(new Integer[0])[0].intValue();
         final int index = getStreamVolume(streamType, device);
 
         if (DEBUG_VOL) {
@@ -4983,6 +4985,8 @@
                     getVssForStreamOrDefault(streamType).getMaxIndex(), streamType);
         } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
             mDeviceBroker.postSetHearingAidVolumeIndex(index * 10, streamType);
+        } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)) {
+            mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index);
         } else {
             return;
         }
@@ -11425,6 +11429,10 @@
         return mSpatializerHelper.canBeSpatialized(attributes, format);
     }
 
+    public @NonNull List<Integer> getSpatializedChannelMasks() {
+        return mSpatializerHelper.getSpatializedChannelMasks();
+    }
+
     /** @see Spatializer.SpatializerInfoDispatcherStub */
     public void registerSpatializerCallback(
             @NonNull ISpatializerCallback cb) {
diff --git a/services/core/java/com/android/server/audio/OWNERS b/services/core/java/com/android/server/audio/OWNERS
index b70de29..709e4c2 100644
--- a/services/core/java/com/android/server/audio/OWNERS
+++ b/services/core/java/com/android/server/audio/OWNERS
@@ -1,2 +1,3 @@
+atneya@google.com
 jmtrivi@google.com
 elaurent@google.com
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index a62ac82..1c01fb9 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -17,13 +17,14 @@
 package com.android.server.audio;
 
 import static android.media.AudioPlaybackConfiguration.EXTRA_PLAYER_EVENT_MUTE;
-import static android.media.AudioPlaybackConfiguration.MUTED_BY_APP_OPS;
+import static android.media.AudioPlaybackConfiguration.MUTED_BY_OP_PLAY_AUDIO;
 import static android.media.AudioPlaybackConfiguration.MUTED_BY_CLIENT_VOLUME;
 import static android.media.AudioPlaybackConfiguration.MUTED_BY_MASTER;
 import static android.media.AudioPlaybackConfiguration.MUTED_BY_PORT_VOLUME;
 import static android.media.AudioPlaybackConfiguration.MUTED_BY_STREAM_MUTED;
 import static android.media.AudioPlaybackConfiguration.MUTED_BY_STREAM_VOLUME;
 import static android.media.AudioPlaybackConfiguration.MUTED_BY_VOLUME_SHAPER;
+import static android.media.AudioPlaybackConfiguration.MUTED_BY_OP_CONTROL_AUDIO;
 import static android.media.AudioPlaybackConfiguration.PLAYER_PIID_INVALID;
 import static android.media.AudioPlaybackConfiguration.PLAYER_UPDATE_MUTED;
 
@@ -1376,8 +1377,8 @@
                         if ((eventValue & MUTED_BY_STREAM_MUTED) != 0) {
                             builder.append("streamMute ");
                         }
-                        if ((eventValue & MUTED_BY_APP_OPS) != 0) {
-                            builder.append("appOps ");
+                        if ((eventValue & MUTED_BY_OP_PLAY_AUDIO) != 0) {
+                            builder.append("opPlayAudio ");
                         }
                         if ((eventValue & MUTED_BY_CLIENT_VOLUME) != 0) {
                             builder.append("clientVolume ");
@@ -1388,6 +1389,10 @@
                         if ((eventValue & MUTED_BY_PORT_VOLUME) != 0) {
                             builder.append("portVolume ");
                         }
+                        if ((eventValue & MUTED_BY_OP_CONTROL_AUDIO) != 0) {
+                            builder.append("opControlAudio ");
+                        }
+
                     }
                     return builder.toString();
                 default:
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 9265ff2..afa90d5 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -59,6 +59,8 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 import java.util.UUID;
@@ -1100,6 +1102,23 @@
         return able;
     }
 
+    synchronized @NonNull List<Integer> getSpatializedChannelMasks() {
+        if (!checkSpatializer("getSpatializedChannelMasks")) {
+            return Collections.emptyList();
+        }
+        try {
+            final int[] nativeMasks = new int[0]; // FIXME mSpat query goes here
+            for (int i = 0; i < nativeMasks.length; i++) {
+                nativeMasks[i] = AudioFormat.convertNativeChannelMaskToOutMask(nativeMasks[i]);
+            }
+            final List<Integer> masks = Arrays.stream(nativeMasks).boxed().toList();
+            return masks;
+        } catch (Exception e) { // just catch Exception in case nativeMasks is null
+            Log.e(TAG, "Error calling getSpatializedChannelMasks", e);
+            return Collections.emptyList();
+        }
+    }
+
     //------------------------------------------------------
     // head tracking
     final RemoteCallbackList<ISpatializerHeadTrackingModeCallback> mHeadTrackingModeCallbacks =
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 97a8854..b365ef7 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -434,21 +434,12 @@
 
         public boolean getMandatoryBiometricsEnabledAndRequirementsSatisfiedForUser(int userId) {
             if (!mMandatoryBiometricsEnabled.containsKey(userId)) {
-                Slog.d(TAG, "update mb toggle for user " + userId);
                 updateMandatoryBiometricsForAllProfiles(userId);
             }
             if (!mMandatoryBiometricsRequirementsSatisfied.containsKey(userId)) {
-                Slog.d(TAG, "update mb reqs for user " + userId);
                 updateMandatoryBiometricsRequirementsForAllProfiles(userId);
             }
 
-            Slog.d(TAG, mMandatoryBiometricsEnabled.getOrDefault(userId,
-                    DEFAULT_MANDATORY_BIOMETRICS_STATUS)
-                    + " " + mMandatoryBiometricsRequirementsSatisfied.getOrDefault(userId,
-                    DEFAULT_MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED_STATUS)
-                    + " " + getEnabledForApps(userId)
-                    + " " + (mFingerprintEnrolledForUser.getOrDefault(userId, false /* default */)
-                    || mFaceEnrolledForUser.getOrDefault(userId, false /* default */)));
             return mMandatoryBiometricsEnabled.getOrDefault(userId,
                     DEFAULT_MANDATORY_BIOMETRICS_STATUS)
                     && mMandatoryBiometricsRequirementsSatisfied.getOrDefault(userId,
diff --git a/services/core/java/com/android/server/biometrics/biometrics.aconfig b/services/core/java/com/android/server/biometrics/biometrics.aconfig
index d3da8dd..95ba695 100644
--- a/services/core/java/com/android/server/biometrics/biometrics.aconfig
+++ b/services/core/java/com/android/server/biometrics/biometrics.aconfig
@@ -34,3 +34,10 @@
       purpose: PURPOSE_BUGFIX
   }
 }
+
+flag {
+  name: "frr_dialog_improvement"
+  namespace: "biometrics_framework"
+  description: "This flag controls FRR dialog improvement"
+  bug: "380800403"
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/PerformanceTracker.java b/services/core/java/com/android/server/biometrics/sensors/PerformanceTracker.java
index eed2bdd..958ab8e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/PerformanceTracker.java
+++ b/services/core/java/com/android/server/biometrics/sensors/PerformanceTracker.java
@@ -18,6 +18,8 @@
 
 import android.util.SparseArray;
 
+import java.util.concurrent.ConcurrentHashMap;
+
 /**
  * Tracks biometric performance across sensors and users.
  */
@@ -25,17 +27,12 @@
 
     private static final String TAG = "PerformanceTracker";
     // Keyed by SensorId
-    private static SparseArray<PerformanceTracker> sTrackers;
+    private static final ConcurrentHashMap<Integer, PerformanceTracker> sTrackers =
+            new ConcurrentHashMap<>();
 
     public static PerformanceTracker getInstanceForSensorId(int sensorId) {
-        if (sTrackers == null) {
-            sTrackers = new SparseArray<>();
-        }
-
-        if (!sTrackers.contains(sensorId)) {
-            sTrackers.put(sensorId, new PerformanceTracker());
-        }
-        return sTrackers.get(sensorId);
+        PerformanceTracker tracker = sTrackers.putIfAbsent(sensorId, new PerformanceTracker());
+        return tracker != null ? tracker : sTrackers.get(sensorId);
     }
 
     private static class Info {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 36e4a7e..944e85c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -851,13 +851,8 @@
             for (int i = 0; i < mFaceSensors.size(); i++) {
                 final Sensor sensor = mFaceSensors.valueAt(i);
                 final int sensorId = mFaceSensors.keyAt(i);
-                final PerformanceTracker performanceTracker = PerformanceTracker.getInstanceForSensorId(
-                        sensorId);
-                if (performanceTracker != null) {
-                    performanceTracker.incrementHALDeathCount();
-                } else {
-                    Slog.w(getTag(), "Performance tracker is null. Not counting HAL death.");
-                }
+                PerformanceTracker.getInstanceForSensorId(sensorId)
+                        .incrementHALDeathCount();
                 sensor.onBinderDied();
             }
         });
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index e1bb8a1..4c5f652 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -26,13 +26,13 @@
 import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
 import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_AUTO;
 import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_AUTO;
+import static android.net.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER;
 import static android.os.PowerWhitelistManager.REASON_VPN;
 import static android.os.UserHandle.PER_USER_RANGE;
 import static android.telephony.CarrierConfigManager.KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT;
 import static android.telephony.CarrierConfigManager.KEY_PREFERRED_IKE_PROTOCOL_INT;
 
 import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
-import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER;
 
 import static java.util.Objects.requireNonNull;
 
@@ -103,6 +103,8 @@
 import android.net.ipsec.ike.exceptions.IkeTimeoutException;
 import android.net.vcn.VcnGatewayConnectionConfig;
 import android.net.vcn.VcnTransportInfo;
+import android.net.vcn.util.MtuUtils;
+import android.net.vcn.util.PersistableBundleUtils;
 import android.os.Binder;
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
@@ -150,8 +152,6 @@
 import com.android.server.DeviceIdleInternal;
 import com.android.server.LocalServices;
 import com.android.server.net.BaseNetworkObserver;
-import com.android.server.vcn.util.MtuUtils;
-import com.android.server.vcn.util.PersistableBundleUtils;
 
 import libcore.io.IoUtils;
 
diff --git a/services/core/java/com/android/server/crashrecovery/CrashRecoveryHelper.java b/services/core/java/com/android/server/crashrecovery/CrashRecoveryHelper.java
index 8e72546..eef2b15 100644
--- a/services/core/java/com/android/server/crashrecovery/CrashRecoveryHelper.java
+++ b/services/core/java/com/android/server/crashrecovery/CrashRecoveryHelper.java
@@ -93,7 +93,8 @@
                     return;
                 }
                 final List<VersionedPackage> pkgList = Collections.singletonList(pkg);
-                PackageWatchdog.getInstance(mContext).onPackageFailure(pkgList,  PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
+                PackageWatchdog.getInstance(mContext).notifyPackageFailure(pkgList,
+                        PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
             });
     }
 
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index d2c044f..1c1bdad 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -311,6 +311,11 @@
      */
     public FrameRateCategoryRate frameRateCategoryRate;
     /**
+     * All the refresh rates supported for the default display mode.
+     */
+    public float[] supportedRefreshRates = new float[0];
+
+    /**
      * The default mode of the display.
      */
     public int defaultModeId;
@@ -562,7 +567,8 @@
                 || installOrientation != other.installOrientation
                 || !Objects.equals(displayShape, other.displayShape)
                 || hasArrSupport != other.hasArrSupport
-                || !Objects.equals(frameRateCategoryRate, other.frameRateCategoryRate)) {
+                || !Objects.equals(frameRateCategoryRate, other.frameRateCategoryRate)
+                || !Arrays.equals(supportedRefreshRates, other.supportedRefreshRates)) {
             diff |= DIFF_OTHER;
         }
         return diff;
@@ -582,6 +588,7 @@
         renderFrameRate = other.renderFrameRate;
         hasArrSupport = other.hasArrSupport;
         frameRateCategoryRate = other.frameRateCategoryRate;
+        supportedRefreshRates = other.supportedRefreshRates;
         defaultModeId = other.defaultModeId;
         userPreferredModeId = other.userPreferredModeId;
         supportedModes = other.supportedModes;
@@ -628,6 +635,7 @@
         sb.append(", renderFrameRate ").append(renderFrameRate);
         sb.append(", hasArrSupport ").append(hasArrSupport);
         sb.append(", frameRateCategoryRate ").append(frameRateCategoryRate);
+        sb.append(", supportedRefreshRates ").append(Arrays.toString(supportedRefreshRates));
         sb.append(", defaultModeId ").append(defaultModeId);
         sb.append(", userPreferredModeId ").append(userPreferredModeId);
         sb.append(", supportedModes ").append(Arrays.toString(supportedModes));
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index ae74dbe..c3cb913 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.display;
 
 import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY;
+import static android.Manifest.permission.ADD_MIRROR_DISPLAY;
 import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;
 import static android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT;
 import static android.Manifest.permission.CAPTURE_VIDEO_OUTPUT;
@@ -1677,8 +1678,8 @@
     }
 
     private boolean canCreateMirrorDisplays(IVirtualDevice virtualDevice) {
-        if (virtualDevice == null) {
-            return false;
+        if (android.companion.virtualdevice.flags.Flags.enableLimitedVdmRole()) {
+            return checkCallingPermission(ADD_MIRROR_DISPLAY, "canCreateMirrorDisplays");
         }
         try {
             return virtualDevice.canCreateMirrorDisplays();
@@ -1818,7 +1819,7 @@
             // display.
             if (!canProjectVideo(projection) && !canCreateMirrorDisplays(virtualDevice)
                     && !hasVideoOutputPermission("createVirtualDisplayInternal")) {
-                throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
+                throw new SecurityException("Requires ADD_MIRROR_DISPLAY, CAPTURE_VIDEO_OUTPUT or "
                         + "CAPTURE_SECURE_VIDEO_OUTPUT permission, or an appropriate "
                         + "MediaProjection token in order to create a screen sharing virtual "
                         + "display. In order to create a virtual display that does not perform "
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index a4bb8c3..0b8f7d5 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -249,6 +249,7 @@
         private int mActiveColorMode;
         private boolean mHasArrSupport;
         private FrameRateCategoryRate mFrameRateCategoryRate;
+        private float[] mSupportedRefreshRates = new float[0];
         private Display.HdrCapabilities mHdrCapabilities;
         private boolean mAllmSupported;
         private boolean mGameContentTypeSupported;
@@ -316,6 +317,7 @@
             changed |= updateGameContentTypeSupport(dynamicInfo.gameContentTypeSupported);
             changed |= updateHasArrSupportLocked(dynamicInfo.hasArrSupport);
             changed |= updateFrameRateCategoryRatesLocked(dynamicInfo.frameRateCategoryRate);
+            changed |= updateSupportedRefreshatesLocked(dynamicInfo.supportedRefreshRates);
 
             if (changed) {
                 mHavePendingChanges = true;
@@ -624,6 +626,20 @@
             return true;
         }
 
+        private boolean updateSupportedRefreshatesLocked(float[] supportedRefreshRates) {
+            if (!getFeatureFlags().enableGetSupportedRefreshRates()) {
+                return false;
+            }
+            if (supportedRefreshRates == null) {
+                return false;
+            }
+            if (Arrays.equals(mSupportedRefreshRates, supportedRefreshRates)) {
+                return false;
+            }
+            mSupportedRefreshRates = supportedRefreshRates;
+            return true;
+        }
+
         private boolean updateAllmSupport(boolean supported) {
             if (mAllmSupported == supported) {
                 return false;
@@ -708,6 +724,7 @@
                 mInfo.hdrCapabilities = mHdrCapabilities;
                 mInfo.hasArrSupport = mHasArrSupport;
                 mInfo.frameRateCategoryRate = mFrameRateCategoryRate;
+                mInfo.supportedRefreshRates = mSupportedRefreshRates;
                 mInfo.appVsyncOffsetNanos = mActiveSfDisplayMode.appVsyncOffsetNanos;
                 mInfo.presentationDeadlineNanos = mActiveSfDisplayMode.presentationDeadlineNanos;
                 mInfo.state = mState;
@@ -1299,6 +1316,7 @@
             pw.println("mDefaultModeId=" + mDefaultModeId);
             pw.println("mUserPreferredModeId=" + mUserPreferredModeId);
             pw.println("mHasArrSupport=" + mHasArrSupport);
+            pw.println("mSupportedRefreshRates=" + Arrays.toString(mSupportedRefreshRates));
             pw.println("mState=" + Display.stateToString(mState));
             pw.println("mCommittedState=" + Display.stateToString(mCommittedState));
             pw.println("mBrightnessState=" + mBrightnessState);
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 7cfdcaf..8546598 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -508,6 +508,8 @@
             mBaseDisplayInfo.renderFrameRate = deviceInfo.renderFrameRate;
             mBaseDisplayInfo.hasArrSupport = deviceInfo.hasArrSupport;
             mBaseDisplayInfo.frameRateCategoryRate = deviceInfo.frameRateCategoryRate;
+            mBaseDisplayInfo.supportedRefreshRates = Arrays.copyOf(
+                    deviceInfo.supportedRefreshRates, deviceInfo.supportedRefreshRates.length);
             mBaseDisplayInfo.defaultModeId = deviceInfo.defaultModeId;
             mBaseDisplayInfo.userPreferredModeId = deviceInfo.userPreferredModeId;
             mBaseDisplayInfo.supportedModes = Arrays.copyOf(
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index dabef84..6ae58c4 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -43,6 +43,7 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.Point;
+import android.hardware.display.IBrightnessListener;
 import android.hardware.display.IVirtualDisplayCallback;
 import android.hardware.display.VirtualDisplayConfig;
 import android.media.projection.IMediaProjection;
@@ -183,8 +184,11 @@
         if (projection != null) {
             mediaProjectionCallback = new MediaProjectionCallback(appToken);
         }
+
+        Callback callbackDelegate = new Callback(
+                callback, virtualDisplayConfig.getBrightnessListener(), mHandler);
         VirtualDisplayDevice device = new VirtualDisplayDevice(displayToken, appToken,
-                ownerUid, ownerPackageName, surface, flags, new Callback(callback, mHandler),
+                ownerUid, ownerPackageName, surface, flags, callbackDelegate,
                 projection, mediaProjectionCallback, uniqueId, virtualDisplayConfig);
 
         mVirtualDisplayDevices.put(appToken, device);
@@ -337,6 +341,7 @@
         private final DisplayCutout mDisplayCutout;
         private final float mDefaultBrightness;
         private float mCurrentBrightness;
+        private final IBrightnessListener mBrightnessListener;
 
         public VirtualDisplayDevice(IBinder displayToken, IBinder appToken,
                 int ownerUid, String ownerPackageName, Surface surface, int flags,
@@ -354,7 +359,8 @@
             mRequestedRefreshRate = virtualDisplayConfig.getRequestedRefreshRate();
             mDisplayCutout = virtualDisplayConfig.getDisplayCutout();
             mDefaultBrightness = virtualDisplayConfig.getDefaultBrightness();
-            mCurrentBrightness = mDefaultBrightness;
+            mCurrentBrightness = PowerManager.BRIGHTNESS_INVALID;
+            mBrightnessListener = virtualDisplayConfig.getBrightnessListener();
             mMode = createMode(mWidth, mHeight, getRefreshRate());
             mSurface = surface;
             mFlags = flags;
@@ -464,6 +470,7 @@
                 }
             }
             if (android.companion.virtualdevice.flags.Flags.deviceAwareDisplayPower()
+                    && mBrightnessListener != null
                     && BrightnessUtils.isValidBrightnessValue(brightnessState)
                     && brightnessState != mCurrentBrightness) {
                 mCurrentBrightness = brightnessState;
@@ -661,10 +668,13 @@
         private static final int MSG_ON_REQUESTED_BRIGHTNESS_CHANGED = 3;
 
         private final IVirtualDisplayCallback mCallback;
+        private final IBrightnessListener mBrightnessListener;
 
-        public Callback(IVirtualDisplayCallback callback, Handler handler) {
+        Callback(IVirtualDisplayCallback callback, IBrightnessListener brightnessListener,
+                Handler handler) {
             super(handler.getLooper());
             mCallback = callback;
+            mBrightnessListener = brightnessListener;
         }
 
         @Override
@@ -681,7 +691,9 @@
                         mCallback.onStopped();
                         break;
                     case MSG_ON_REQUESTED_BRIGHTNESS_CHANGED:
-                        mCallback.onRequestedBrightnessChanged((Float) msg.obj);
+                        if (mBrightnessListener != null) {
+                            mBrightnessListener.onBrightnessChanged((Float) msg.obj);
+                        }
                         break;
                 }
             } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index 7f46bbb..45106f5 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -243,6 +243,11 @@
             Flags::autoBrightnessModeBedtimeWear
     );
 
+    private final FlagState mGetSupportedRefreshRatesFlagState = new FlagState(
+            Flags.FLAG_ENABLE_GET_SUPPORTED_REFRESH_RATES,
+            Flags::enableGetSupportedRefreshRates
+    );
+
     private final FlagState mEnablePluginManagerFlagState = new FlagState(
             Flags.FLAG_ENABLE_PLUGIN_MANAGER,
             Flags::enablePluginManager
@@ -252,6 +257,11 @@
             Flags::displayListenerPerformanceImprovements
     );
 
+    private final FlagState mSubscribeGranularDisplayEvents = new FlagState(
+            Flags.FLAG_SUBSCRIBE_GRANULAR_DISPLAY_EVENTS,
+            Flags::subscribeGranularDisplayEvents
+    );
+
     /**
      * @return {@code true} if 'port' is allowed in display layout configuration file.
      */
@@ -528,6 +538,13 @@
         return mAutoBrightnessModeBedtimeWearFlagState.isEnabled();
     }
 
+    /**
+     * @return {@code true} if supported refresh rate api is enabled.
+     */
+    public boolean enableGetSupportedRefreshRates() {
+        return mGetSupportedRefreshRatesFlagState.isEnabled();
+    }
+
     public boolean isPluginManagerEnabled() {
         return mEnablePluginManagerFlagState.isEnabled();
     }
@@ -540,6 +557,13 @@
     }
 
     /**
+     * @return {@code true} if the flag for subscribing to granular display events is enabled
+     */
+    public boolean isSubscribeGranularDisplayEventsEnabled() {
+        return mSubscribeGranularDisplayEvents.isEnabled();
+    }
+
+    /**
      * dumps all flagstates
      * @param pw printWriter
      */
@@ -590,8 +614,10 @@
         pw.println(" " + mIsUserRefreshRateForExternalDisplayEnabled);
         pw.println(" " + mHasArrSupport);
         pw.println(" " + mAutoBrightnessModeBedtimeWearFlagState);
+        pw.println(" " + mGetSupportedRefreshRatesFlagState);
         pw.println(" " + mEnablePluginManagerFlagState);
         pw.println(" " + mDisplayListenerPerformanceImprovementsFlagState);
+        pw.println(" " + mSubscribeGranularDisplayEvents);
     }
 
     private static class FlagState {
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index e7ea868..3976d01 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -478,3 +478,14 @@
     bug: "378385869"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "subscribe_granular_display_events"
+    namespace: "display_manager"
+    description: "Enable subscription to granular display change events."
+    bug: "379250634"
+    is_fixed_read_only: true
+    metadata {
+      purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 0e7d2b6..a06f9ef 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -524,6 +524,13 @@
     static final String PROPERTY_DISABLE_CEC_ON_STANDBY_IN_LOW_ENERGY_MODE =
             "persist.sys.hdmi.property_disable_cec_on_standby_in_low_energy_mode";
 
+    /**
+     * Property that checks if CEC was manually enabled by the user in offline mode. With the help
+     * of this property we avoid turning off CEC when the device goes to sleep and if the device
+     * is in low energy mode.
+     */
+    static final String PROPERTY_USER_ACTION_KEEP_CEC_ENABLED_IN_OFFLINE_MODE =
+            "persist.sys.hdmi.property_user_action_keep_cec_enabled_in_offline_mode";
     static final int RECORDING_TYPE_DIGITAL_RF = 1;
     static final int RECORDING_TYPE_ANALOGUE_RF = 2;
     static final int RECORDING_TYPE_EXTERNAL_PHYSICAL_ADDRESS = 3;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java b/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java
index 53c0217..2e66fbc 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java
@@ -16,6 +16,8 @@
 
 package com.android.server.hdmi;
 
+import static android.media.tv.flags.Flags.hdmiControlCollectPhysicalAddress;
+
 import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_ARC_PENDING;
 import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_EARC_CONNECTED;
 import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_EARC_PENDING;
@@ -35,6 +37,8 @@
     @VisibleForTesting
     protected static final int FEATURE_ABORT_OPCODE_UNKNOWN = 0x100;
     private static final int ERROR_CODE_UNKNOWN = -1;
+    @VisibleForTesting
+    protected static final int PHYSICAL_ADDRESS_INVALID = 0xFFFF;
 
     /**
      * Writes a HdmiCecMessageReported atom representing an HDMI CEC message.
@@ -95,6 +99,11 @@
                 return createUserControlPressedSpecialArgs(message);
             case Constants.MESSAGE_FEATURE_ABORT:
                 return createFeatureAbortSpecialArgs(message);
+            case Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS:
+                if (hdmiControlCollectPhysicalAddress()) {
+                    return createReportPhysicalAddressSpecialArgs(message);
+                }
+                return new MessageReportedSpecialArgs();
             default:
                 return new MessageReportedSpecialArgs();
         }
@@ -140,6 +149,23 @@
     }
 
     /**
+     * Constructs the special arguments for a <Report Physical Address> message.
+     *
+     * @param message The HDMI CEC message to log
+     */
+    private MessageReportedSpecialArgs createReportPhysicalAddressSpecialArgs(
+            HdmiCecMessage message) {
+        MessageReportedSpecialArgs specialArgs = new MessageReportedSpecialArgs();
+
+        if (message.getParams().length > 1) {
+            int physicalAddress = (message.getParams()[0] << 8) | message.getParams()[1];
+            specialArgs.mPhysicalAddress = physicalAddress;
+        }
+
+        return specialArgs;
+    }
+
+    /**
      * Writes a HdmiCecMessageReported atom.
      *
      * @param genericArgs Generic arguments; shared by all HdmiCecMessageReported atoms
@@ -156,7 +182,8 @@
                 genericArgs.mSendMessageResult,
                 specialArgs.mUserControlPressedCommand,
                 specialArgs.mFeatureAbortOpcode,
-                specialArgs.mFeatureAbortReason);
+                specialArgs.mFeatureAbortReason,
+                specialArgs.mPhysicalAddress);
     }
 
     /**
@@ -166,7 +193,7 @@
     protected void writeHdmiCecMessageReportedAtom(int uid, int direction,
             int initiatorLogicalAddress, int destinationLogicalAddress, int opcode,
             int sendMessageResult, int userControlPressedCommand, int featureAbortOpcode,
-            int featureAbortReason) {
+            int featureAbortReason, int physicalAddress) {
         FrameworkStatsLog.write(
                 FrameworkStatsLog.HDMI_CEC_MESSAGE_REPORTED,
                 uid,
@@ -177,7 +204,8 @@
                 sendMessageResult,
                 userControlPressedCommand,
                 featureAbortOpcode,
-                featureAbortReason);
+                featureAbortReason,
+                physicalAddress);
     }
 
     /**
@@ -284,5 +312,6 @@
         int mUserControlPressedCommand = HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN;
         int mFeatureAbortOpcode = FEATURE_ABORT_OPCODE_UNKNOWN;
         int mFeatureAbortReason = HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN;
+        int mPhysicalAddress = PHYSICAL_ADDRESS_INVALID;
     }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 0c5069f..f049ef3 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -725,6 +725,13 @@
         }
         mPowerStatusController.setPowerStatus(getInitialPowerStatus());
         setProhibitMode(false);
+        if (isTvDevice() && getWasCecDisabledOnStandbyByLowEnergyMode()) {
+            Slog.w(TAG, "Re-enable CEC on boot-up since it was disabled due to low energy "
+                    + " mode.");
+            mHdmiCecConfig.setIntValue(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+                    HDMI_CEC_CONTROL_ENABLED);
+            setWasCecDisabledOnStandbyByLowEnergyMode(false);
+        }
         mHdmiControlEnabled = mHdmiCecConfig.getIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
 
@@ -771,14 +778,6 @@
             Slog.i(TAG, "Device does not support eARC.");
         }
         mHdmiCecNetwork = new HdmiCecNetwork(this, mCecController, mMhlController);
-        if (isTvDevice() && getWasCecDisabledOnStandbyByLowEnergyMode()) {
-            Slog.w(TAG, "Re-enable CEC on boot-up since it was disabled due to low energy "
-                    + " mode.");
-            getHdmiCecConfig().setIntValue(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
-                    HDMI_CEC_CONTROL_ENABLED);
-            setWasCecDisabledOnStandbyByLowEnergyMode(false);
-            setCecEnabled(HDMI_CEC_CONTROL_ENABLED);
-        }
         if (isCecControlEnabled()) {
             initializeCec(INITIATED_BY_BOOT_UP);
         } else {
@@ -4027,7 +4026,8 @@
                     return;
                 }
                 if (isTvDevice() && getDisableCecOnStandbyByLowEnergyMode()
-                        && mPowerManager.isLowPowerStandbyEnabled()) {
+                        && mPowerManager.isLowPowerStandbyEnabled()
+                        && !userEnabledCecInOfflineMode()) {
                     Slog.w(TAG, "Disable CEC on standby due to low power energy mode.");
                     setWasCecDisabledOnStandbyByLowEnergyMode(true);
                     getHdmiCecConfig().setIntValue(
@@ -5225,4 +5225,14 @@
                 Constants.PROPERTY_WAS_CEC_DISABLED_ON_STANDBY_BY_LOW_ENERGY_MODE,
                 String.valueOf(value));
     }
+
+    /**
+     * Reads the property that checks if CEC was enabled by the user while in offline mode such that
+     * it won't be disabled when going to sleep by low energy mode.
+     */
+    @VisibleForTesting
+    protected boolean userEnabledCecInOfflineMode() {
+        return SystemProperties.getBoolean(
+                Constants.PROPERTY_USER_ACTION_KEEP_CEC_ENABLED_IN_OFFLINE_MODE, false);
+    }
 }
diff --git a/services/core/java/com/android/server/incident/PendingReports.java b/services/core/java/com/android/server/incident/PendingReports.java
index 35b3673..9a6c87e 100644
--- a/services/core/java/com/android/server/incident/PendingReports.java
+++ b/services/core/java/com/android/server/incident/PendingReports.java
@@ -324,16 +324,12 @@
 
         // Allow system apps to skip the consent dialog and use their in-built consent mechanism
         // instead.
-        boolean captureConsentlessBugreportDelegatedConsentGranted = false;
-        if ((flags & IncidentManager.FLAG_ALLOW_CONSENTLESS_BUGREPORT) != 0) {
-            captureConsentlessBugreportDelegatedConsentGranted =
-                    mPermissionManager.checkPermissionForDataDelivery(
-                                    Manifest.permission
-                                            .CAPTURE_CONSENTLESS_BUGREPORT_DELEGATED_CONSENT,
-                                    attributionSource,
-                                    /* message= */ null)
-                            == PERMISSION_GRANTED;
-        }
+        boolean captureConsentlessBugreportDelegatedConsentGranted =
+                mPermissionManager.checkPermissionForDataDelivery(
+                        Manifest.permission.CAPTURE_CONSENTLESS_BUGREPORT_DELEGATED_CONSENT,
+                        attributionSource,
+                        /* message= */ null)
+                        == PERMISSION_GRANTED;
 
         if (captureConsentlessBugreportOnUserdebugBuildGranted
                 || captureConsentlessBugreportDelegatedConsentGranted) {
diff --git a/services/core/java/com/android/server/input/InputShellCommand.java b/services/core/java/com/android/server/input/InputShellCommand.java
index 9833016..5bc08a0 100644
--- a/services/core/java/com/android/server/input/InputShellCommand.java
+++ b/services/core/java/com/android/server/input/InputShellCommand.java
@@ -475,6 +475,7 @@
                 }
             }
         }
+        event = KeyEvent.changeTimeRepeat(event, SystemClock.uptimeMillis(), 0);
         injectKeyEvent(KeyEvent.changeAction(event, KeyEvent.ACTION_UP), async);
     }
 
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
index d132449..da20891 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
@@ -19,13 +19,19 @@
 import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 
 import android.annotation.NonNull;
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.Region;
 import android.os.InputConfig;
 import android.os.Process;
+import android.util.Slog;
 import android.view.InputApplicationHandle;
 import android.view.InputChannel;
 import android.view.InputWindowHandle;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
+import android.view.WindowMetrics;
+import android.view.inputmethod.Flags;
 
 import com.android.server.input.InputManagerService;
 
@@ -39,8 +45,8 @@
     private final SurfaceControl mInputSurface;
     private boolean mIsIntercepting;
 
-    HandwritingEventReceiverSurface(String name, int displayId, @NonNull SurfaceControl sc,
-            @NonNull InputChannel inputChannel) {
+    HandwritingEventReceiverSurface(Context context, String name, int displayId,
+            @NonNull SurfaceControl sc, @NonNull InputChannel inputChannel) {
         mClientChannel = inputChannel;
         mInputSurface = sc;
 
@@ -59,15 +65,31 @@
                         | InputConfig.SPY
                         | InputConfig.INTERCEPTS_STYLUS;
 
-        // Configure the surface to receive stylus events across the entire display.
-        mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
+        Rect bounds = null;
+        if (Flags.adaptiveHandwritingBounds()) {
+            mWindowHandle.setTouchableRegionCrop(mInputSurface);
+            // Default touchable area to getMaximumWindowMetrics()
+            WindowMetrics windowMetrics =  context.getSystemService(WindowManager.class)
+                    .getMaximumWindowMetrics();
+            bounds = windowMetrics.getBounds();
+            if (DEBUG) Slog.d(TAG, "initial handwriting touchable bounds: " + bounds);
+            mWindowHandle.setTouchableRegion(windowMetrics.getBounds());
+        } else {
+            // Configure the surface to receive stylus events across the entire display.
+            mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
+        }
 
         final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
         mWindowHandle.setTrustedOverlay(t, mInputSurface, true);
         t.setInputWindowInfo(mInputSurface, mWindowHandle);
         t.setLayer(mInputSurface, InputManagerService.INPUT_OVERLAY_LAYER_HANDWRITING_SURFACE);
         t.setPosition(mInputSurface, 0, 0);
-        t.setCrop(mInputSurface, null /* crop to parent surface */);
+        if (Flags.adaptiveHandwritingBounds()) {
+            // crop to parent surface if null, else bounds.
+            t.setCrop(mInputSurface, bounds);
+        } else {
+            t.setCrop(mInputSurface, null /* crop to parent surface */);
+        }
         t.show(mInputSurface);
         t.apply();
 
@@ -79,12 +101,23 @@
         mWindowHandle.ownerUid = imeUid;
         mWindowHandle.inputConfig &= ~InputConfig.SPY;
 
+        if (Flags.adaptiveHandwritingBounds()) {
+            // watch outside touch to finish handwriting.
+            mWindowHandle.inputConfig |= InputConfig.WATCH_OUTSIDE_TOUCH;
+        }
         new SurfaceControl.Transaction()
                 .setInputWindowInfo(mInputSurface, mWindowHandle)
                 .apply();
         mIsIntercepting = true;
     }
 
+    void setTouchableRegion(Region touchableRegion) {
+        mWindowHandle.touchableRegion.set(touchableRegion);
+        new SurfaceControl.Transaction()
+                .setInputWindowInfo(mInputSurface, mWindowHandle)
+                .apply();
+    }
+
     void setNotTouchable(boolean notTouchable) {
         if (notTouchable) {
             mWindowHandle.inputConfig |= InputConfig.NOT_TOUCHABLE;
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
index c19cb03..45d7d04 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
@@ -27,6 +27,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManagerInternal;
+import android.graphics.Region;
 import android.hardware.input.InputManager;
 import android.hardware.input.InputManagerGlobal;
 import android.os.Handler;
@@ -139,7 +140,7 @@
         }
 
         mHandwritingSurface = new HandwritingEventReceiverSurface(
-                name, displayId, surface, channel);
+                mContext, name, displayId, surface, channel);
 
         // Use a dup of the input channel so that event processing can be paused by disposing the
         // event receiver without causing a fd hangup.
@@ -163,6 +164,13 @@
         mHandwritingSurface.setNotTouchable(notTouchable);
     }
 
+    void setHandwritingTouchableRegion(Region region) {
+        if (!getCurrentRequestId().isPresent()) {
+            return;
+        }
+        mHandwritingSurface.setTouchableRegion(region);
+    }
+
     boolean isStylusGestureOngoing() {
         if (mRecordingGestureAfterStylusUp && !mHandwritingBuffer.isEmpty()) {
             // If it is less than AFTER_STYLUS_UP_ALLOW_PERIOD_MS after the stylus up event, return
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index b7af9a4..02dd884 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -84,6 +84,7 @@
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
+import android.graphics.Region;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.input.InputManager;
 import android.inputmethodservice.InputMethodService;
@@ -6888,6 +6889,14 @@
 
         @BinderThread
         @Override
+        public void setHandwritingTouchableRegion(Region region) {
+            synchronized (ImfLock.class) {
+                mImms.mHwController.setHandwritingTouchableRegion(region);
+            }
+        }
+
+        @BinderThread
+        @Override
         public void createInputContentUriToken(Uri contentUri, String packageName,
                 AndroidFuture future /* T=IBinder */) {
             @SuppressWarnings("unchecked") final AndroidFuture<IBinder> typedFuture = future;
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 76049ca..d177d0e 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -34,6 +34,7 @@
 import android.hardware.contexthub.HubEndpointInfo;
 import android.hardware.contexthub.IContextHubEndpoint;
 import android.hardware.contexthub.IContextHubEndpointCallback;
+import android.hardware.contexthub.IContextHubEndpointDiscoveryCallback;
 import android.hardware.contexthub.MessageDeliveryStatus;
 import android.hardware.location.ContextHubInfo;
 import android.hardware.location.ContextHubMessage;
@@ -793,6 +794,31 @@
         return null;
     }
 
+    @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+    @Override
+    public void registerEndpointDiscoveryCallbackId(
+            long endpointId, IContextHubEndpointDiscoveryCallback callback) throws RemoteException {
+        super.registerEndpointDiscoveryCallbackId_enforcePermission();
+        // TODO(b/375487784): Implement this
+    }
+
+    @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+    @Override
+    public void registerEndpointDiscoveryCallbackDescriptor(
+            String serviceDescriptor, IContextHubEndpointDiscoveryCallback callback)
+            throws RemoteException {
+        super.registerEndpointDiscoveryCallbackDescriptor_enforcePermission();
+        // TODO(b/375487784): Implement this
+    }
+
+    @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+    @Override
+    public void unregisterEndpointDiscoveryCallback(IContextHubEndpointDiscoveryCallback callback)
+            throws RemoteException {
+        super.unregisterEndpointDiscoveryCallback_enforcePermission();
+        // TODO(b/375487784): Implement this
+    }
+
     /**
      * Creates an internal load transaction callback to be used for old API clients
      *
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
index da31bf2..ccfa61b 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
@@ -492,14 +492,21 @@
     /* package */
     void onTransactionResponse(int transactionId, boolean success) {
         TransactionAcceptConditions conditions =
-                transaction -> transaction.getTransactionId() == transactionId;
+                transaction -> {
+                    if (transaction.getTransactionId() != transactionId) {
+                        Log.w(
+                                TAG,
+                                "Unexpected transaction: expected "
+                                        + transactionId
+                                        + ", received "
+                                        + transaction.getTransactionId());
+                        return false;
+                    }
+                    return true;
+                };
         ContextHubServiceTransaction transaction = getTransactionAndHandleNext(conditions);
         if (transaction == null) {
-            Log.w(TAG, "Received unexpected transaction response (expected ID = "
-                    + transactionId
-                    + ", received ID = "
-                    + transaction.getTransactionId()
-                    + ")");
+            Log.w(TAG, "Received unexpected transaction response");
             return;
         }
 
@@ -581,7 +588,7 @@
                 transaction.getTransactionType() == ContextHubTransaction.TYPE_QUERY_NANOAPPS;
         ContextHubServiceTransaction transaction = getTransactionAndHandleNext(conditions);
         if (transaction == null) {
-            Log.w(TAG, "Received unexpected query response (expected " + transaction + ")");
+            Log.w(TAG, "Received unexpected query response");
             return;
         }
 
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 27bc1cf..2d2d258 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -221,6 +221,11 @@
         }
     }
 
+    @NonNull
+    private SystemMediaRoute2Provider getSystemProviderForUser(@NonNull UserHandler userHandler) {
+        return userHandler.mSystemProvider;
+    }
+
     // Start of methods that implement MediaRouter2 operations.
 
     @NonNull
@@ -246,7 +251,7 @@
                 UserRecord userRecord = getOrCreateUserRecordLocked(userId);
                 if (hasSystemRoutingPermissions) {
                     MediaRoute2ProviderInfo providerInfo =
-                            userRecord.mHandler.mSystemProvider.getProviderInfo();
+                            getSystemProviderForUser(userRecord.mHandler).getProviderInfo();
                     if (providerInfo != null) {
                         systemRoutes = providerInfo.getRoutes();
                     } else {
@@ -258,7 +263,8 @@
                     }
                 } else {
                     systemRoutes = new ArrayList<>();
-                    systemRoutes.add(userRecord.mHandler.mSystemProvider.getDefaultRoute());
+                    systemRoutes.add(
+                            getSystemProviderForUser(userRecord.mHandler).getDefaultRoute());
                 }
             }
             return new ArrayList<>(systemRoutes);
@@ -850,10 +856,11 @@
                     if (setDeviceRouteSelected) {
                         // Return a fake system session that shows the device route as selected and
                         // available bluetooth routes as transferable.
-                        return userRecord.mHandler.mSystemProvider
+                        return getSystemProviderForUser(userRecord.mHandler)
                                 .generateDeviceRouteSelectedSessionInfo(targetPackageName);
                     } else {
-                        sessionInfos = userRecord.mHandler.mSystemProvider.getSessionInfos();
+                        sessionInfos = getSystemProviderForUser(userRecord.mHandler)
+                                .getSessionInfos();
                         if (!sessionInfos.isEmpty()) {
                             // Return a copy of the current system session with no modification,
                             // except setting the client package name.
@@ -866,7 +873,8 @@
                     }
                 } else {
                     return new RoutingSessionInfo.Builder(
-                                    userRecord.mHandler.mSystemProvider.getDefaultSessionInfo())
+                                    getSystemProviderForUser(userRecord.mHandler)
+                                            .getDefaultSessionInfo())
                             .setClientPackageName(targetPackageName)
                             .build();
                 }
@@ -1374,7 +1382,7 @@
             }
             manager.mLastSessionCreationRequest = null;
         } else {
-            String defaultRouteId = userHandler.mSystemProvider.getDefaultRoute().getId();
+            String defaultRouteId = getSystemProviderForUser(userHandler).getDefaultRoute().getId();
             if (route.isSystemRoute()
                     && !routerRecord.hasSystemRoutingPermission()
                     && !TextUtils.equals(route.getId(), defaultRouteId)) {
@@ -1462,7 +1470,7 @@
                         routerRecord.mPackageName, routerRecord.mRouterId, route.getId()));
 
         UserHandler userHandler = routerRecord.mUserRecord.mHandler;
-        String defaultRouteId = userHandler.mSystemProvider.getDefaultRoute().getId();
+        String defaultRouteId = getSystemProviderForUser(userHandler).getDefaultRoute().getId();
         if (route.isSystemRoute()
                 && !routerRecord.hasSystemRoutingPermission()
                 && !TextUtils.equals(route.getId(), defaultRouteId)) {
@@ -2125,11 +2133,12 @@
                 notifyRoutesUpdated(routesToReport.values().stream().toList());
 
                 List<RoutingSessionInfo> sessionInfos =
-                        mUserRecord.mHandler.mSystemProvider.getSessionInfos();
+                        getSystemProviderForUser(mUserRecord.mHandler).getSessionInfos();
                 RoutingSessionInfo systemSessionToReport =
                         newSystemRoutingPermissionValue && !sessionInfos.isEmpty()
                                 ? sessionInfos.get(0)
-                                : mUserRecord.mHandler.mSystemProvider.getDefaultSessionInfo();
+                                : getSystemProviderForUser(mUserRecord.mHandler)
+                                        .getDefaultSessionInfo();
                 notifySessionInfoChanged(systemSessionToReport);
             }
         }
@@ -2279,7 +2288,7 @@
                 if (route.isSystemRoute() && !hasSystemRoutingPermission()) {
                     // The router lacks permission to modify system routing, so we hide system
                     // route info from them.
-                    route = mUserRecord.mHandler.mSystemProvider.getDefaultRoute();
+                    route = getSystemProviderForUser(mUserRecord.mHandler).getDefaultRoute();
                 }
                 mRouter.requestCreateSessionByManager(uniqueRequestId, oldSession, route);
             } catch (RemoteException ex) {
@@ -2535,6 +2544,10 @@
 
         private boolean mRunning;
 
+        private SystemMediaRoute2Provider getSystemProvider() {
+            return mSystemProvider;
+        }
+
         // TODO: (In Android S+) Pull out SystemMediaRoute2Provider out of UserHandler.
         UserHandler(
                 @NonNull MediaRouter2ServiceImpl service,
@@ -2544,21 +2557,24 @@
             mServiceRef = new WeakReference<>(service);
             mUserRecord = userRecord;
             mSystemProvider =
-                    new SystemMediaRoute2Provider(
-                            service.mContext, UserHandle.of(userRecord.mUserId), looper);
-            mRouteProviders.add(mSystemProvider);
+                    Flags.enableMirroringInMediaRouter2()
+                            ? new SystemMediaRoute2Provider2(
+                                    service.mContext, UserHandle.of(userRecord.mUserId), looper)
+                            : new SystemMediaRoute2Provider(
+                                    service.mContext, UserHandle.of(userRecord.mUserId), looper);
+            mRouteProviders.add(getSystemProvider());
             mWatcher = new MediaRoute2ProviderWatcher(service.mContext, this,
                     this, mUserRecord.mUserId);
         }
 
         void init() {
-            mSystemProvider.setCallback(this);
+            getSystemProvider().setCallback(this);
         }
 
         private void start() {
             if (!mRunning) {
                 mRunning = true;
-                mSystemProvider.start();
+                getSystemProvider().start();
                 mWatcher.start();
             }
         }
@@ -2567,7 +2583,7 @@
             if (mRunning) {
                 mRunning = false;
                 mWatcher.stop(); // also stops all providers
-                mSystemProvider.stop();
+                getSystemProvider().stop();
             }
         }
 
@@ -2659,7 +2675,7 @@
             String indent = prefix + "  ";
             pw.println(indent + "mRunning=" + mRunning);
 
-            mSystemProvider.dump(pw, prefix);
+            getSystemProvider().dump(pw, prefix);
             mWatcher.dump(pw, prefix);
         }
 
@@ -2752,7 +2768,7 @@
                     hasAddedOrModifiedRoutes,
                     hasRemovedRoutes,
                     provider.mIsSystemRouteProvider,
-                    mSystemProvider.getDefaultRoute());
+                    getSystemProvider().getDefaultRoute());
         }
 
         private static String getPackageNameFromNullableRecord(
@@ -2966,7 +2982,8 @@
             }
 
             // Bypass checking router if it's the system session (routerRecord should be null)
-            if (TextUtils.equals(getProviderId(uniqueSessionId), mSystemProvider.getUniqueId())) {
+            if (TextUtils.equals(
+                    getProviderId(uniqueSessionId), getSystemProvider().getUniqueId())) {
                 return true;
             }
 
@@ -3097,7 +3114,7 @@
                     && !matchingRequest.mRouterRecord.hasSystemRoutingPermission()) {
                 // The router lacks permission to modify system routing, so we hide system routing
                 // session info from them.
-                sessionInfo = mSystemProvider.getDefaultSessionInfo();
+                sessionInfo = getSystemProvider().getDefaultSessionInfo();
             }
             matchingRequest.mRouterRecord.notifySessionCreated(
                     toOriginalRequestId(uniqueRequestId), sessionInfo);
@@ -3111,13 +3128,13 @@
             }
 
             // For system provider, notify all routers.
-            if (provider == mSystemProvider) {
+            if (provider == getSystemProvider()) {
                 if (mServiceRef.get() == null) {
                     return;
                 }
                 notifySessionInfoChangedToRouters(getRouterRecords(true), sessionInfo);
                 notifySessionInfoChangedToRouters(
-                        getRouterRecords(false), mSystemProvider.getDefaultSessionInfo());
+                        getRouterRecords(false), getSystemProvider().getDefaultSessionInfo());
                 return;
             }
 
@@ -3253,7 +3270,8 @@
             MediaRoute2ProviderInfo systemProviderInfo = null;
             for (MediaRoute2ProviderInfo providerInfo : mLastProviderInfos) {
                 // TODO: Create MediaRoute2ProviderInfo#isSystemProvider()
-                if (TextUtils.equals(providerInfo.getUniqueId(), mSystemProvider.getUniqueId())) {
+                if (TextUtils.equals(
+                        providerInfo.getUniqueId(), getSystemProvider().getUniqueId())) {
                     // Adding routes from system provider will be handled below, so skip it here.
                     systemProviderInfo = providerInfo;
                     continue;
@@ -3269,10 +3287,10 @@
                     // This shouldn't happen.
                     Slog.wtf(TAG, "System route provider not found.");
                 }
-                currentSystemSessionInfo = mSystemProvider.getSessionInfos().get(0);
+                currentSystemSessionInfo = getSystemProvider().getSessionInfos().get(0);
             } else {
-                currentRoutes.add(mSystemProvider.getDefaultRoute());
-                currentSystemSessionInfo = mSystemProvider.getDefaultSessionInfo();
+                currentRoutes.add(getSystemProvider().getDefaultRoute());
+                currentSystemSessionInfo = getSystemProvider().getDefaultSessionInfo();
             }
 
             if (!currentRoutes.isEmpty()) {
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java
new file mode 100644
index 0000000..a86e818
--- /dev/null
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 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.media;
+
+import android.content.Context;
+import android.media.MediaRoute2ProviderService;
+import android.os.Looper;
+import android.os.UserHandle;
+
+/**
+ * Extends {@link SystemMediaRoute2Provider} by adding system routes provided by {@link
+ * MediaRoute2ProviderService provider services}.
+ *
+ * <p>System routes are those which can handle the system audio and/or video.
+ */
+/* package */ class SystemMediaRoute2Provider2 extends SystemMediaRoute2Provider {
+    SystemMediaRoute2Provider2(Context context, UserHandle user, Looper looper) {
+        super(context, user, looper);
+    }
+}
diff --git a/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java b/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java
index 6c74cba..05fe781 100644
--- a/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java
+++ b/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java
@@ -30,7 +30,8 @@
             int hostUid,
             int targetUid,
             int timeSinceLastActive,
-            int creationSource) {
+            int creationSource,
+            int stopSource) {
         FrameworkStatsLog.write(
                 code,
                 sessionId,
@@ -39,7 +40,8 @@
                 hostUid,
                 targetUid,
                 timeSinceLastActive,
-                creationSource);
+                creationSource,
+                stopSource);
     }
 
     /** Wrapper around {@link FrameworkStatsLog#write} for MediaProjectionTargetChanged atom. */
@@ -49,13 +51,23 @@
             int targetType,
             int hostUid,
             int targetUid,
-            int windowingMode) {
+            int windowingMode,
+            int width,
+            int height,
+            int centerX,
+            int centerY,
+            int targetChangeType) {
         FrameworkStatsLog.write(
                 code,
                 sessionId,
                 targetType,
                 hostUid,
                 targetUid,
-                windowingMode);
+                windowingMode,
+                width,
+                height,
+                centerX,
+                centerY,
+                targetChangeType);
     }
 }
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index df5ecf8..c428f39 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -51,6 +51,7 @@
 import android.content.pm.PackageManager.ApplicationInfoFlags;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ServiceInfo;
+import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
 import android.media.MediaRouter;
 import android.media.projection.IMediaProjection;
@@ -60,6 +61,7 @@
 import android.media.projection.MediaProjectionInfo;
 import android.media.projection.MediaProjectionManager;
 import android.media.projection.ReviewGrantedConsentResult;
+import android.media.projection.StopReason;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
@@ -178,7 +180,7 @@
             if (!mMediaProjectionStopController.isExemptFromStopping(mProjectionGrant, reason)) {
                 Slog.d(TAG, "Content Recording: Stopping MediaProjection due to "
                         + MediaProjectionStopController.stopReasonToString(reason));
-                mProjectionGrant.stop();
+                mProjectionGrant.stop(StopReason.STOP_DEVICE_LOCKED);
             }
         }
     }
@@ -257,7 +259,7 @@
         synchronized (mLock) {
             if (mProjectionGrant != null) {
                 Slog.d(TAG, "Content Recording: Stopped MediaProjection due to user switching");
-                mProjectionGrant.stop();
+                mProjectionGrant.stop(StopReason.STOP_USER_SWITCH);
             }
         }
     }
@@ -295,7 +297,7 @@
             Slog.d(TAG,
                     "Content Recording: Stopped MediaProjection due to foreground service change");
             if (mProjectionGrant != null) {
-                mProjectionGrant.stop();
+                mProjectionGrant.stop(StopReason.STOP_FOREGROUND_SERVICE_CHANGE);
             }
         }
     }
@@ -304,7 +306,7 @@
         if (mProjectionGrant != null) {
             Slog.d(TAG, "Content Recording: Stopped MediaProjection to start new "
                     + "incoming projection");
-            mProjectionGrant.stop();
+            mProjectionGrant.stop(StopReason.STOP_NEW_PROJECTION);
         }
         if (mMediaRouteInfo != null) {
             mMediaRouter.getFallbackRoute().select();
@@ -314,7 +316,10 @@
         dispatchStart(projection);
     }
 
-    private void stopProjectionLocked(final MediaProjection projection) {
+    private void stopProjectionLocked(
+            final MediaProjection projection,
+            @StopReason int stopReason
+    ) {
         Slog.d(TAG, "Content Recording: Stopped active MediaProjection and "
                 + "dispatching stop to callbacks");
         ContentRecordingSession session = projection.mSession;
@@ -322,7 +327,7 @@
                 session != null
                         ? session.getTargetUid()
                         : ContentRecordingSession.TARGET_UID_UNKNOWN;
-        mMediaProjectionMetricsLogger.logStopped(projection.uid, targetUid);
+        mMediaProjectionMetricsLogger.logStopped(projection.uid, targetUid, stopReason);
         mProjectionToken = null;
         mProjectionGrant = null;
         dispatchStop(projection);
@@ -403,7 +408,7 @@
                             + "ContentRecordingSession - id= "
                             + mProjectionGrant.getVirtualDisplayId() + "type=" + projectionType);
 
-                    mProjectionGrant.stop();
+                    mProjectionGrant.stop(StopReason.STOP_ERROR);
                 }
                 return false;
             }
@@ -517,6 +522,18 @@
         }
     }
 
+    @VisibleForTesting
+    void notifyCaptureBoundsChanged(int contentToRecord, int targetUid, Rect captureBounds) {
+        synchronized (mLock) {
+            if (mProjectionGrant == null) {
+                Slog.i(TAG, "Cannot log MediaProjectionTargetChanged atom due to null projection");
+            } else {
+                mMediaProjectionMetricsLogger.logChangedCaptureBounds(
+                        contentToRecord, mProjectionGrant.uid, targetUid, captureBounds);
+            }
+        }
+    }
+
     /**
      * Handles result of dialog shown from
      * {@link BinderService#buildReviewGrantedConsentIntentLocked()}.
@@ -557,7 +574,7 @@
                         Slog.w(TAG, "Content Recording: Stopped MediaProjection due to user "
                                 + "consent result of CANCEL - "
                                 + "id= " + mProjectionGrant.getVirtualDisplayId());
-                        mProjectionGrant.stop();
+                        mProjectionGrant.stop(StopReason.STOP_ERROR);
                     }
                     break;
                 case RECORD_CONTENT_DISPLAY:
@@ -773,14 +790,14 @@
 
         @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
         @Override // Binder call
-        public void stopActiveProjection() {
+        public void stopActiveProjection(@StopReason int stopReason) {
             stopActiveProjection_enforcePermission();
             final long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
                     if (mProjectionGrant != null) {
                         Slog.d(TAG, "Content Recording: Stopping active projection");
-                        mProjectionGrant.stop();
+                        mProjectionGrant.stop(stopReason);
                     }
                 }
             } finally {
@@ -790,8 +807,9 @@
 
         @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
         @Override // Binder call
-        public void notifyActiveProjectionCapturedContentResized(int width, int height) {
-            notifyActiveProjectionCapturedContentResized_enforcePermission();
+        public void notifyCaptureBoundsChanged(
+                int contentToRecord, int targetProcessUid, Rect newBounds) {
+            notifyCaptureBoundsChanged_enforcePermission();
             synchronized (mLock) {
                 if (!isCurrentProjection(mProjectionGrant)) {
                     return;
@@ -801,7 +819,13 @@
             try {
                 synchronized (mLock) {
                     if (mProjectionGrant != null && mCallbackDelegate != null) {
-                        mCallbackDelegate.dispatchResize(mProjectionGrant, width, height);
+                        // log metrics for the new bounds
+                        MediaProjectionManagerService.this.notifyCaptureBoundsChanged(
+                                contentToRecord, targetProcessUid, newBounds);
+
+                        // update clients of the new update bounds
+                        mCallbackDelegate.dispatchResize(
+                                mProjectionGrant, newBounds.width(), newBounds.height());
                     }
                 }
             } finally {
@@ -1133,7 +1157,7 @@
                         Slog.d(TAG, "Content Recording: MediaProjection stopped by Binder death - "
                                 + "id= " + mVirtualDisplayId);
                         mCallbackDelegate.remove(callback);
-                        stop();
+                        stop(StopReason.STOP_TARGET_REMOVED);
                     };
                     mToken.linkToDeath(mDeathEater, 0);
                 } catch (RemoteException e) {
@@ -1182,7 +1206,7 @@
         }
 
         @Override // Binder call
-        public void stop() {
+        public void stop(@StopReason int stopReason) {
             synchronized (mLock) {
                 if (!isCurrentProjection(asBinder())) {
                     Slog.w(TAG, "Attempted to stop inactive MediaProjection "
@@ -1211,7 +1235,7 @@
                 Slog.d(TAG, "Content Recording: handling stopping this projection token"
                         + " createTime= " + mCreateTimeMillis
                         + " countStarts= " + mCountStarts);
-                stopProjectionLocked(this);
+                stopProjectionLocked(this, stopReason);
                 mToken.unlinkToDeath(mDeathEater, 0);
                 mToken = null;
                 unregisterCallback(mCallback);
@@ -1295,7 +1319,7 @@
                     Slog.v(TAG, "Reusing token: Throw exception due to invalid projection.");
                     // Tear down projection here; necessary to ensure (among other reasons) that
                     // stop is dispatched to client and cast icon disappears from status bar.
-                    mProjectionGrant.stop();
+                    mProjectionGrant.stop(StopReason.STOP_ERROR);
                     throw new SecurityException("Don't re-use the resultData to retrieve "
                             + "the same projection instance, and don't use a token that has "
                             + "timed out. Don't take multiple captures by invoking "
@@ -1315,10 +1339,9 @@
                     Slog.w(TAG,
                             "Content Recording: MediaProjection start disallowed, aborting "
                                     + "MediaProjection");
-                    stop();
+                    stop(StopReason.STOP_DEVICE_LOCKED);
                     return;
                 }
-
                 mVirtualDisplayId = displayId;
 
                 // If prior session was does not have a valid display id, then update the display
@@ -1357,7 +1380,7 @@
                     if (mProjectionGrant != null) {
                         Slog.d(TAG, "Content Recording: Stopped MediaProjection due to "
                                 + "route type of REMOTE_DISPLAY not selected");
-                        mProjectionGrant.stop();
+                        mProjectionGrant.stop(StopReason.STOP_NEW_MEDIA_ROUTE);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java b/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java
index be2a25a..8e5c016 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java
@@ -19,15 +19,34 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY;
 import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
 
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_DEVICE_LOCK;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_ERROR;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_FOREGROUND_SERVICE_CHANGE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_HOST_APP_STOP;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_MEDIA_ROUTE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_PROJECTION;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_QS_TILE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_STATUS_BAR_CHIP_STOP;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_TASK_APP_CLOSE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_APP_SELECTOR_DISPLAYED;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_USER_SWITCH;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_BOUNDS;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_POSITION;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_WINDOWING_MODE;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_APP_TASK;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_DISPLAY;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_UNKNOWN;
@@ -36,8 +55,12 @@
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_SPLIT_SCREEN;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_UNKNOWN;
 
+import android.app.WindowConfiguration;
 import android.app.WindowConfiguration.WindowingMode;
 import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.media.projection.StopReason;
 import android.util.Log;
 import android.view.ContentRecordingSession.RecordContent;
 
@@ -59,8 +82,10 @@
     private final MediaProjectionSessionIdGenerator mSessionIdGenerator;
     private final MediaProjectionTimestampStore mTimestampStore;
 
-    private int mPreviousState =
-            FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN;
+    private final Rect mPreviousTargetBounds = new Rect();
+    private int mPreviousTargetWindowingMode = WINDOWING_MODE_UNDEFINED;
+    private int mPreviousProjectionState =
+            MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN;
 
     MediaProjectionMetricsLogger(
             FrameworkStatsLogWrapper frameworkStatsLogWrapper,
@@ -113,7 +138,8 @@
                 hostUid,
                 TARGET_UID_UNKNOWN,
                 timeSinceLastActiveInSeconds,
-                sessionCreationSource);
+                sessionCreationSource,
+                MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
     }
 
     /**
@@ -130,7 +156,8 @@
                 hostUid,
                 TARGET_UID_UNKNOWN,
                 TIME_SINCE_LAST_ACTIVE_UNKNOWN,
-                MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+                MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN,
+                MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
     }
 
     /**
@@ -141,13 +168,12 @@
     public void logProjectionPermissionRequestCancelled(int hostUid) {
         writeStateChanged(
                 mSessionIdGenerator.getCurrentSessionId(),
-                FrameworkStatsLog
-                        .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED,
+                MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED,
                 hostUid,
                 TARGET_UID_UNKNOWN,
                 TIME_SINCE_LAST_ACTIVE_UNKNOWN,
-                FrameworkStatsLog
-                        .MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+                MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN,
+                MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
     }
 
     /**
@@ -163,7 +189,8 @@
                 hostUid,
                 TARGET_UID_UNKNOWN,
                 TIME_SINCE_LAST_ACTIVE_UNKNOWN,
-                MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+                MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN,
+                MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
     }
 
     /**
@@ -180,7 +207,8 @@
                 hostUid,
                 targetUid,
                 TIME_SINCE_LAST_ACTIVE_UNKNOWN,
-                MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+                MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN,
+                MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
     }
 
     /**
@@ -196,14 +224,63 @@
      */
     public void logChangedWindowingMode(
             int contentToRecord, int hostUid, int targetUid, int windowingMode) {
-        Log.d(TAG, "logChangedWindowingMode");
+        Log.d(TAG, "logChangedWindowingMode: windowingMode= "
+                + WindowConfiguration.windowingModeToString(windowingMode));
+        Log.d(TAG, "targetChangeType= changeWindowingMode");
         writeTargetChanged(
                 mSessionIdGenerator.getCurrentSessionId(),
                 contentToRecordToTargetType(contentToRecord),
                 hostUid,
                 targetUid,
-                windowingModeToTargetWindowingMode(windowingMode));
+                windowingModeToTargetWindowingMode(windowingMode),
+                mPreviousTargetBounds.width(),
+                mPreviousTargetBounds.height(),
+                mPreviousTargetBounds.centerX(),
+                mPreviousTargetBounds.centerY(),
+                MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_WINDOWING_MODE);
+        mPreviousTargetWindowingMode = windowingMode;
+    }
 
+    /**
+     * Logs that the bounds of projection's capture target has changed.
+     *
+     * @param contentToRecord ContentRecordingSession.RecordContent indicating whether it is a
+     *                        task capture or display capture - gets converted to the corresponding
+     *                        TargetType before being logged.
+     * @param hostUid UID of the package that initiates MediaProjection.
+     * @param targetUid UID of the package that is captured if selected.
+     * @param captureBounds Updated bounds of the captured region.
+     */
+    public void logChangedCaptureBounds(
+            int contentToRecord, int hostUid, int targetUid, Rect captureBounds) {
+        final Point capturePosition = new Point(captureBounds.centerX(), captureBounds.centerY());
+        Log.d(TAG, "logChangedCaptureBounds: captureBounds= " + captureBounds + " position= "
+                + capturePosition);
+
+        writeTargetChanged(
+                mSessionIdGenerator.getCurrentSessionId(),
+                contentToRecordToTargetType(contentToRecord),
+                hostUid,
+                targetUid,
+                mPreviousTargetWindowingMode,
+                captureBounds.width(),
+                captureBounds.height(),
+                captureBounds.centerX(),
+                captureBounds.centerY(),
+                captureBoundsToTargetChangeType(captureBounds));
+        mPreviousTargetBounds.set(captureBounds);
+    }
+
+    private int captureBoundsToTargetChangeType(Rect captureBounds) {
+        final boolean hasChangedSize = captureBounds.width() != mPreviousTargetBounds.width()
+                && captureBounds.height() != mPreviousTargetBounds.height();
+
+        if (hasChangedSize) {
+            Log.d(TAG, "targetChangeType= changeBounds");
+            return MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_BOUNDS;
+        }
+        Log.d(TAG, "targetChangeType= changePosition");
+        return MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_POSITION;
     }
 
     @VisibleForTesting
@@ -231,45 +308,85 @@
         };
     }
 
+    @VisibleForTesting
+    public int stopReasonToSessionStopSource(@StopReason int stopReason) {
+        return switch (stopReason) {
+            case StopReason.STOP_HOST_APP ->
+                    MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_HOST_APP_STOP;
+            case StopReason.STOP_TARGET_REMOVED ->
+                    MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_TASK_APP_CLOSE;
+            case StopReason.STOP_DEVICE_LOCKED->
+                    MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_DEVICE_LOCK;
+            case StopReason.STOP_PRIVACY_CHIP ->
+                    MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_STATUS_BAR_CHIP_STOP;
+            case StopReason.STOP_QS_TILE ->
+                    MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_QS_TILE;
+            case StopReason.STOP_USER_SWITCH ->
+                    MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_USER_SWITCH;
+            case StopReason.STOP_FOREGROUND_SERVICE_CHANGE ->
+                    MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_FOREGROUND_SERVICE_CHANGE;
+            case StopReason.STOP_NEW_PROJECTION ->
+                    MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_PROJECTION;
+            case StopReason.STOP_NEW_MEDIA_ROUTE ->
+                    MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_MEDIA_ROUTE;
+            case StopReason.STOP_ERROR ->
+                    MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_ERROR;
+            default ->
+                    MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN;
+        };
+    }
+
     /**
      * Logs that the capturing stopped, either normally or because of error.
      *
      * @param hostUid UID of the package that initiates MediaProjection.
      * @param targetUid UID of the package that is captured if selected.
      */
-    public void logStopped(int hostUid, int targetUid) {
+    public void logStopped(int hostUid, int targetUid, int stopReason) {
         boolean wasCaptureInProgress =
-                mPreviousState
+                mPreviousProjectionState
                         == MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS;
-        Log.d(TAG, "logStopped: wasCaptureInProgress=" + wasCaptureInProgress);
+        Log.d(TAG, "logStopped: wasCaptureInProgress=" + wasCaptureInProgress +
+                " stopReason=" + stopReason);
         writeStateChanged(
                 mSessionIdGenerator.getCurrentSessionId(),
                 MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED,
                 hostUid,
                 targetUid,
                 TIME_SINCE_LAST_ACTIVE_UNKNOWN,
-                MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+                MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN,
+                stopReasonToSessionStopSource(stopReason));
 
         if (wasCaptureInProgress) {
             mTimestampStore.registerActiveSessionEnded();
         }
     }
 
-    public void notifyProjectionStateChange(int hostUid, int state, int sessionCreationSource) {
-        writeStateChanged(hostUid, state, sessionCreationSource);
+    public void notifyProjectionStateChange(
+            int hostUid,
+            int state,
+            int sessionCreationSource,
+            int sessionStopSource
+    ) {
+        writeStateChanged(hostUid, state, sessionCreationSource, sessionStopSource);
     }
 
-    private void writeStateChanged(int hostUid, int state, int sessionCreationSource) {
+    private void writeStateChanged(
+            int hostUid,
+            int state,
+            int sessionCreationSource,
+            int sessionStopSource
+    ) {
         mFrameworkStatsLogWrapper.writeStateChanged(
-                /* code */ FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED,
+                /* code */ MEDIA_PROJECTION_STATE_CHANGED,
                 /* session_id */ 123,
                 /* state */ state,
-                /* previous_state */ FrameworkStatsLog
-                        .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN,
+                /* previous_state */ MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN,
                 /* host_uid */ hostUid,
                 /* target_uid */ -1,
                 /* time_since_last_active */ 0,
-                /* creation_source */ sessionCreationSource);
+                /* creation_source */ sessionCreationSource,
+                /* stop_source */ sessionStopSource);
     }
 
     private void writeStateChanged(
@@ -278,17 +395,19 @@
             int hostUid,
             int targetUid,
             int timeSinceLastActive,
-            int creationSource) {
+            int creationSource,
+            int stopSource) {
         mFrameworkStatsLogWrapper.writeStateChanged(
-                /* code */ FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED,
+                /* code */ MEDIA_PROJECTION_STATE_CHANGED,
                 sessionId,
                 state,
-                mPreviousState,
+                mPreviousProjectionState,
                 hostUid,
                 targetUid,
                 timeSinceLastActive,
-                creationSource);
-        mPreviousState = state;
+                creationSource,
+                stopSource);
+        mPreviousProjectionState = state;
     }
 
     private void writeTargetChanged(
@@ -296,13 +415,23 @@
             int targetType,
             int hostUid,
             int targetUid,
-            int targetWindowingMode) {
+            int targetWindowingMode,
+            int width,
+            int height,
+            int centerX,
+            int centerY,
+            int targetChangeType) {
         mFrameworkStatsLogWrapper.writeTargetChanged(
-                /* code */ FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED,
+                /* code */ MEDIA_PROJECTION_TARGET_CHANGED,
                 sessionId,
                 targetType,
                 hostUid,
                 targetUid,
-                targetWindowingMode);
+                targetWindowingMode,
+                width,
+                height,
+                centerX,
+                centerY,
+                targetChangeType);
     }
 }
diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java
index c7e00d3..65d0ab3 100644
--- a/services/core/java/com/android/server/media/quality/MediaQualityService.java
+++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java
@@ -25,7 +25,7 @@
 import android.media.quality.IMediaQualityManager;
 import android.media.quality.IPictureProfileCallback;
 import android.media.quality.ISoundProfileCallback;
-import android.media.quality.MediaQualityContract;
+import android.media.quality.MediaQualityContract.BaseParameters;
 import android.media.quality.ParamCapability;
 import android.media.quality.PictureProfile;
 import android.media.quality.PictureProfileHandle;
@@ -42,6 +42,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
+import java.util.stream.Collectors;
 
 /**
  * This service manage picture profile and sound profile for TV setting. Also communicates with the
@@ -71,14 +72,14 @@
     private final class BinderService extends IMediaQualityManager.Stub {
 
         @Override
-        public PictureProfile createPictureProfile(PictureProfile pp) {
+        public PictureProfile createPictureProfile(PictureProfile pp, int userId) {
             SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
 
             ContentValues values = new ContentValues();
-            values.put(MediaQualityContract.BaseParameters.PARAMETER_TYPE, pp.getProfileType());
-            values.put(MediaQualityContract.BaseParameters.PARAMETER_NAME, pp.getName());
-            values.put(MediaQualityContract.BaseParameters.PARAMETER_PACKAGE, pp.getPackageName());
-            values.put(MediaQualityContract.BaseParameters.PARAMETER_INPUT_ID, pp.getInputId());
+            values.put(BaseParameters.PARAMETER_TYPE, pp.getProfileType());
+            values.put(BaseParameters.PARAMETER_NAME, pp.getName());
+            values.put(BaseParameters.PARAMETER_PACKAGE, pp.getPackageName());
+            values.put(BaseParameters.PARAMETER_INPUT_ID, pp.getInputId());
             values.put(mMediaQualityDbHelper.SETTINGS, bundleToJson(pp.getParameters()));
 
             // id is auto-generated by SQLite upon successful insertion of row
@@ -87,20 +88,21 @@
         }
 
         @Override
-        public void updatePictureProfile(String id, PictureProfile pp) {
-            // TODO: implement
-        }
-        @Override
-        public void removePictureProfile(String id) {
+        public void updatePictureProfile(String id, PictureProfile pp, int userId) {
             // TODO: implement
         }
 
         @Override
-        public PictureProfile getPictureProfile(int type, String name) {
+        public void removePictureProfile(String id, int userId) {
+            // TODO: implement
+        }
+
+        @Override
+        public PictureProfile getPictureProfile(int type, String name, int userId) {
             SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase();
 
-            String selection = MediaQualityContract.BaseParameters.PARAMETER_TYPE + " = ? AND "
-                    + MediaQualityContract.BaseParameters.PARAMETER_NAME + " = ?";
+            String selection = BaseParameters.PARAMETER_TYPE + " = ? AND "
+                    + BaseParameters.PARAMETER_NAME + " = ?";
             String[] selectionArguments = {Integer.toString(type), name};
 
             try (
@@ -176,26 +178,26 @@
 
         private String[] getAllPictureProfileColumns() {
             return new String[]{
-                    MediaQualityContract.BaseParameters.PARAMETER_ID,
-                    MediaQualityContract.BaseParameters.PARAMETER_TYPE,
-                    MediaQualityContract.BaseParameters.PARAMETER_NAME,
-                    MediaQualityContract.BaseParameters.PARAMETER_INPUT_ID,
-                    MediaQualityContract.BaseParameters.PARAMETER_PACKAGE,
+                    BaseParameters.PARAMETER_ID,
+                    BaseParameters.PARAMETER_TYPE,
+                    BaseParameters.PARAMETER_NAME,
+                    BaseParameters.PARAMETER_INPUT_ID,
+                    BaseParameters.PARAMETER_PACKAGE,
                     mMediaQualityDbHelper.SETTINGS
             };
         }
 
         private PictureProfile getPictureProfileFromCursor(Cursor cursor) {
             String returnId = cursor.getString(cursor.getColumnIndexOrThrow(
-                    MediaQualityContract.BaseParameters.PARAMETER_ID));
+                    BaseParameters.PARAMETER_ID));
             int type = cursor.getInt(cursor.getColumnIndexOrThrow(
-                    MediaQualityContract.BaseParameters.PARAMETER_TYPE));
+                    BaseParameters.PARAMETER_TYPE));
             String name = cursor.getString(cursor.getColumnIndexOrThrow(
-                    MediaQualityContract.BaseParameters.PARAMETER_NAME));
+                    BaseParameters.PARAMETER_NAME));
             String inputId = cursor.getString(cursor.getColumnIndexOrThrow(
-                    MediaQualityContract.BaseParameters.PARAMETER_INPUT_ID));
+                    BaseParameters.PARAMETER_INPUT_ID));
             String packageName = cursor.getString(cursor.getColumnIndexOrThrow(
-                    MediaQualityContract.BaseParameters.PARAMETER_PACKAGE));
+                    BaseParameters.PARAMETER_PACKAGE));
             String settings = cursor.getString(
                     cursor.getColumnIndexOrThrow(mMediaQualityDbHelper.SETTINGS));
             return new PictureProfile(returnId, type, name, inputId,
@@ -203,28 +205,26 @@
         }
 
         @Override
-        public List<PictureProfile> getPictureProfilesByPackage(String packageName) {
-            String selection = MediaQualityContract.BaseParameters.PARAMETER_PACKAGE + " = ?";
+        public List<PictureProfile> getPictureProfilesByPackage(String packageName, int userId) {
+            String selection = BaseParameters.PARAMETER_PACKAGE + " = ?";
             String[] selectionArguments = {packageName};
             return getPictureProfilesBasedOnConditions(getAllPictureProfileColumns(), selection,
                     selectionArguments);
         }
 
         @Override
-        public List<PictureProfile> getAvailablePictureProfiles() {
+        public List<PictureProfile> getAvailablePictureProfiles(int userId) {
             return new ArrayList<>();
         }
 
         @Override
-        public List<String> getPictureProfilePackageNames() {
-            String [] column = {MediaQualityContract.BaseParameters.PARAMETER_NAME};
+        public List<String> getPictureProfilePackageNames(int userId) {
+            String [] column = {BaseParameters.PARAMETER_NAME};
             List<PictureProfile> pictureProfiles = getPictureProfilesBasedOnConditions(column,
                     null, null);
-            List<String> packageNames = new ArrayList<>();
-            for (PictureProfile pictureProfile: pictureProfiles) {
-                packageNames.add(pictureProfile.getName());
-            }
-            return packageNames;
+            return pictureProfiles.stream()
+                    .map(PictureProfile::getName)
+                    .collect(Collectors.toList());
         }
 
         private List<PictureProfile> getPictureProfilesBasedOnConditions(String[] columns,
@@ -250,40 +250,140 @@
         }
 
         @Override
-        public PictureProfileHandle getPictureProfileHandle(String id) {
+        public PictureProfileHandle getPictureProfileHandle(String id, int userId) {
             return null;
         }
 
         @Override
-        public SoundProfile createSoundProfile(SoundProfile pp) {
-            // TODO: implement
-            return pp;
+        public SoundProfile createSoundProfile(SoundProfile sp, int userId) {
+            SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
+
+            ContentValues values = new ContentValues();
+            values.put(BaseParameters.PARAMETER_NAME, sp.getName());
+            values.put(BaseParameters.PARAMETER_PACKAGE, sp.getPackageName());
+            values.put(BaseParameters.PARAMETER_INPUT_ID, sp.getInputId());
+            values.put(mMediaQualityDbHelper.SETTINGS, bundleToJson(sp.getParameters()));
+
+            long id = db.insert(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, null, values);
+            return new SoundProfile.Builder(sp).setProfileId(Long.toString(id)).build();
         }
+
         @Override
-        public void updateSoundProfile(String id, SoundProfile pp) {
+        public void updateSoundProfile(String id, SoundProfile pp, int userId) {
             // TODO: implement
         }
+
         @Override
-        public void removeSoundProfile(String id) {
-            // TODO: implement
+        public void removeSoundProfile(String id, int userId) {
+            SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
+            String selection = BaseParameters.PARAMETER_ID + " = ?";
+            String[] selectionArgs = {id};
+            db.delete(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, selection, selectionArgs);
         }
+
         @Override
-        public SoundProfile getSoundProfile(int type, String id) {
-            return null;
+        public SoundProfile getSoundProfile(int type, String id, int userId) {
+            SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase();
+
+            String selection = BaseParameters.PARAMETER_ID + " = ?";
+            String[] selectionArguments = {id};
+
+            try (
+                    Cursor cursor = db.query(
+                            mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME,
+                            getAllSoundProfileColumns(),
+                            selection,
+                            selectionArguments,
+                            /*groupBy=*/ null,
+                            /*having=*/ null,
+                            /*orderBy=*/ null)
+            ) {
+                int count = cursor.getCount();
+                if (count == 0) {
+                    return null;
+                }
+                if (count > 1) {
+                    Log.wtf(TAG, String.format(Locale.US, "%d entries found for id=%s"
+                                    + " in %s. Should only ever be 0 or 1.", count, id,
+                            mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME));
+                    return null;
+                }
+                cursor.moveToFirst();
+                return getSoundProfileFromCursor(cursor);
+            }
         }
+
         @Override
-        public List<SoundProfile> getSoundProfilesByPackage(String packageName) {
-            return new ArrayList<>();
+        public List<SoundProfile> getSoundProfilesByPackage(String packageName, int userId) {
+            String selection = BaseParameters.PARAMETER_PACKAGE + " = ?";
+            String[] selectionArguments = {packageName};
+            return getSoundProfilesBasedOnConditions(getAllSoundProfileColumns(), selection,
+                    selectionArguments);
         }
+
         @Override
-        public List<SoundProfile> getAvailableSoundProfiles() {
-            return new ArrayList<>();
-        }
-        @Override
-        public List<String> getSoundProfilePackageNames() {
+        public List<SoundProfile> getAvailableSoundProfiles(int userId) {
             return new ArrayList<>();
         }
 
+        @Override
+        public List<String> getSoundProfilePackageNames(int userId) {
+            String [] column = {BaseParameters.PARAMETER_NAME};
+            List<SoundProfile> soundProfiles = getSoundProfilesBasedOnConditions(column,
+                    null, null);
+            return soundProfiles.stream()
+                    .map(SoundProfile::getName)
+                    .collect(Collectors.toList());
+        }
+
+        private String[] getAllSoundProfileColumns() {
+            return new String[]{
+                    BaseParameters.PARAMETER_ID,
+                    BaseParameters.PARAMETER_NAME,
+                    BaseParameters.PARAMETER_INPUT_ID,
+                    BaseParameters.PARAMETER_PACKAGE,
+                    mMediaQualityDbHelper.SETTINGS
+            };
+        }
+
+        private SoundProfile getSoundProfileFromCursor(Cursor cursor) {
+            String returnId = cursor.getString(
+                    cursor.getColumnIndexOrThrow(BaseParameters.PARAMETER_ID));
+            int type = cursor.getInt(
+                    cursor.getColumnIndexOrThrow(BaseParameters.PARAMETER_TYPE));
+            String name = cursor.getString(
+                    cursor.getColumnIndexOrThrow(BaseParameters.PARAMETER_NAME));
+            String inputId = cursor.getString(
+                    cursor.getColumnIndexOrThrow(BaseParameters.PARAMETER_INPUT_ID));
+            String packageName = cursor.getString(
+                    cursor.getColumnIndexOrThrow(BaseParameters.PARAMETER_PACKAGE));
+            String settings = cursor.getString(
+                    cursor.getColumnIndexOrThrow(mMediaQualityDbHelper.SETTINGS));
+            return new SoundProfile(returnId, type, name, inputId, packageName,
+                    jsonToBundle(settings));
+        }
+
+        private List<SoundProfile> getSoundProfilesBasedOnConditions(String[] columns,
+                String selection, String[] selectionArguments) {
+            SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase();
+
+            try (
+                    Cursor cursor = db.query(
+                            mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME,
+                            columns,
+                            selection,
+                            selectionArguments,
+                            /*groupBy=*/ null,
+                            /*having=*/ null,
+                            /*orderBy=*/ null)
+            ) {
+                List<SoundProfile> soundProfiles = new ArrayList<>();
+                while (cursor.moveToNext()) {
+                    soundProfiles.add(getSoundProfileFromCursor(cursor));
+                }
+                return soundProfiles;
+            }
+        }
 
         @Override
         public void registerPictureProfileCallback(final IPictureProfileCallback callback) {
@@ -297,70 +397,70 @@
         }
 
         @Override
-        public void setAmbientBacklightSettings(AmbientBacklightSettings settings) {
+        public void setAmbientBacklightSettings(AmbientBacklightSettings settings, int userId) {
         }
 
         @Override
-        public void setAmbientBacklightEnabled(boolean enabled) {
+        public void setAmbientBacklightEnabled(boolean enabled, int userId) {
         }
 
         @Override
-        public List<ParamCapability> getParamCapabilities(List<String> names) {
+        public List<ParamCapability> getParamCapabilities(List<String> names, int userId) {
             return new ArrayList<>();
         }
 
         @Override
-        public List<String> getPictureProfileAllowList() {
+        public List<String> getPictureProfileAllowList(int userId) {
             return new ArrayList<>();
         }
 
         @Override
-        public void setPictureProfileAllowList(List<String> packages) {
+        public void setPictureProfileAllowList(List<String> packages, int userId) {
         }
 
         @Override
-        public List<String> getSoundProfileAllowList() {
+        public List<String> getSoundProfileAllowList(int userId) {
             return new ArrayList<>();
         }
 
         @Override
-        public void setSoundProfileAllowList(List<String> packages) {
+        public void setSoundProfileAllowList(List<String> packages, int userId) {
         }
 
         @Override
-        public boolean isSupported() {
+        public boolean isSupported(int userId) {
             return false;
         }
 
         @Override
-        public void setAutoPictureQualityEnabled(boolean enabled) {
+        public void setAutoPictureQualityEnabled(boolean enabled, int userId) {
         }
 
         @Override
-        public boolean isAutoPictureQualityEnabled() {
+        public boolean isAutoPictureQualityEnabled(int userId) {
             return false;
         }
 
         @Override
-        public void setSuperResolutionEnabled(boolean enabled) {
+        public void setSuperResolutionEnabled(boolean enabled, int userId) {
         }
 
         @Override
-        public boolean isSuperResolutionEnabled() {
+        public boolean isSuperResolutionEnabled(int userId) {
             return false;
         }
 
         @Override
-        public void setAutoSoundQualityEnabled(boolean enabled) {
+        public void setAutoSoundQualityEnabled(boolean enabled, int userId) {
         }
 
         @Override
-        public boolean isAutoSoundQualityEnabled() {
+        public boolean isAutoSoundQualityEnabled(int userId) {
             return false;
         }
 
         @Override
-        public boolean isAmbientBacklightEnabled() {
+        public boolean isAmbientBacklightEnabled(int userId) {
             return false;
         }
     }
diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java
index 7fd9620..f914551 100644
--- a/services/core/java/com/android/server/notification/GroupHelper.java
+++ b/services/core/java/com/android/server/notification/GroupHelper.java
@@ -755,36 +755,7 @@
                     Log.i(TAG, "isGroupChildWithoutSummary OR isGroupSummaryWithoutChild"
                             + record);
                 }
-
-                ArrayMap<String, NotificationAttributes> ungrouped =
-                        mUngroupedAbuseNotifications.getOrDefault(fullAggregateGroupKey,
-                            new ArrayMap<>());
-                ungrouped.put(record.getKey(), new NotificationAttributes(
-                    record.getFlags(),
-                    record.getNotification().getSmallIcon(),
-                    record.getNotification().color,
-                    record.getNotification().visibility,
-                    record.getNotification().getGroupAlertBehavior(),
-                    record.getChannel().getId()));
-                mUngroupedAbuseNotifications.put(fullAggregateGroupKey, ungrouped);
-                // Create/update summary and group if >= mAutoGroupAtCount notifications
-                //  or if aggregate group exists
-                boolean hasSummary = !mAggregatedNotifications.getOrDefault(fullAggregateGroupKey,
-                    new ArrayMap<>()).isEmpty();
-                if (ungrouped.size() >= mAutoGroupAtCount || hasSummary) {
-                    if (DEBUG) {
-                        if (ungrouped.size() >= mAutoGroupAtCount) {
-                            Log.i(TAG,
-                                "Found >=" + mAutoGroupAtCount
-                                    + " ungrouped notifications => force grouping");
-                        } else {
-                            Log.i(TAG, "Found aggregate summary => force grouping");
-                        }
-                    }
-                    aggregateUngroupedNotifications(fullAggregateGroupKey, sbn.getKey(),
-                            ungrouped, hasSummary, sectioner.mSummaryId);
-                }
-
+                addToUngroupedAndMaybeAggregate(record, fullAggregateGroupKey, sectioner);
                 return;
             }
 
@@ -815,6 +786,38 @@
         }
     }
 
+    @GuardedBy("mAggregatedNotifications")
+    private void addToUngroupedAndMaybeAggregate(NotificationRecord record,
+            FullyQualifiedGroupKey fullAggregateGroupKey, NotificationSectioner sectioner) {
+        ArrayMap<String, NotificationAttributes> ungrouped =
+                mUngroupedAbuseNotifications.getOrDefault(fullAggregateGroupKey,
+                    new ArrayMap<>());
+        ungrouped.put(record.getKey(), new NotificationAttributes(
+                record.getFlags(),
+                record.getNotification().getSmallIcon(),
+                record.getNotification().color,
+                record.getNotification().visibility,
+                record.getNotification().getGroupAlertBehavior(),
+                record.getChannel().getId()));
+        mUngroupedAbuseNotifications.put(fullAggregateGroupKey, ungrouped);
+        // Create/update summary and group if >= mAutoGroupAtCount notifications
+        //  or if aggregate group exists
+        boolean hasSummary = !mAggregatedNotifications.getOrDefault(fullAggregateGroupKey,
+                new ArrayMap<>()).isEmpty();
+        if (ungrouped.size() >= mAutoGroupAtCount || hasSummary) {
+            if (DEBUG) {
+                if (ungrouped.size() >= mAutoGroupAtCount) {
+                    Slog.i(TAG, "Found >=" + mAutoGroupAtCount
+                            + " ungrouped notifications => force grouping");
+                } else {
+                    Slog.i(TAG, "Found aggregate summary => force grouping");
+                }
+            }
+            aggregateUngroupedNotifications(fullAggregateGroupKey, record.getKey(),
+                    ungrouped, hasSummary, sectioner.mSummaryId);
+        }
+    }
+
     private static boolean isGroupChildBundled(final NotificationRecord record,
             final Map<String, NotificationRecord> summaryByGroupKey) {
         final StatusBarNotification sbn = record.getSbn();
@@ -897,6 +900,73 @@
         }
     }
 
+    /**
+     * Called when a child notification is removed, after some delay, so that this helper can
+     * trigger a forced grouping if the group has become sparse/singleton
+     * or only the summary is left.
+     *
+     * see also {@link #onNotificationPostedWithDelay(NotificationRecord, List, Map)}
+     *
+     * @param summaryRecord the group summary of the notification that was removed
+     * @param notificationList the full notification list from NotificationManagerService
+     * @param summaryByGroupKey the map of group summaries from NotificationManagerService
+     */
+    @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPING)
+    protected void onGroupedNotificationRemovedWithDelay(final NotificationRecord summaryRecord,
+            final List<NotificationRecord> notificationList,
+            final Map<String, NotificationRecord> summaryByGroupKey) {
+        final StatusBarNotification sbn = summaryRecord.getSbn();
+        if (!sbn.isAppGroup()) {
+            return;
+        }
+
+        if (summaryRecord.isCanceled) {
+            return;
+        }
+
+        if (mIsTestHarnessExempted) {
+            return;
+        }
+
+        final NotificationSectioner sectioner = getSection(summaryRecord);
+        if (sectioner == null) {
+            if (DEBUG) {
+                Slog.i(TAG,
+                        "Skipping autogrouping for " + summaryRecord + " no valid section found.");
+            }
+            return;
+        }
+
+        final String pkgName = sbn.getPackageName();
+        final FullyQualifiedGroupKey fullAggregateGroupKey = new FullyQualifiedGroupKey(
+                summaryRecord.getUserId(), pkgName, sectioner);
+
+        // This notification is already aggregated
+        if (summaryRecord.getGroupKey().equals(fullAggregateGroupKey.toString())) {
+            return;
+        }
+
+        synchronized (mAggregatedNotifications) {
+            if (isGroupSummaryWithoutChildren(summaryRecord, notificationList)) {
+                if (DEBUG) {
+                    Slog.i(TAG, "isGroupSummaryWithoutChild " + summaryRecord);
+                }
+                addToUngroupedAndMaybeAggregate(summaryRecord, fullAggregateGroupKey, sectioner);
+                return;
+            }
+
+            // Check if notification removal turned this group into a sparse/singleton group
+            if (Flags.notificationForceGroupSingletons()) {
+                try {
+                    groupSparseGroups(summaryRecord, notificationList, summaryByGroupKey, sectioner,
+                            fullAggregateGroupKey);
+                } catch (Throwable e) {
+                    Slog.wtf(TAG, "Failed to group sparse groups", e);
+                }
+            }
+        }
+    }
+
     private record NotificationMoveOp(NotificationRecord record, FullyQualifiedGroupKey oldGroup,
                                       FullyQualifiedGroupKey newGroup) { }
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 5182dfe..15af36b 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -26,6 +26,7 @@
 import static android.app.AppOpsManager.OP_RECEIVE_SENSITIVE_NOTIFICATIONS;
 import static android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR;
 import static android.app.Flags.lifetimeExtensionRefactor;
+import static android.app.Flags.notificationClassificationUi;
 import static android.app.Flags.sortSectionByTime;
 import static android.app.Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
 import static android.app.Notification.EXTRA_BUILDER_APPLICATION_INFO;
@@ -4225,6 +4226,22 @@
         }
 
         @Override
+        @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+        public @NonNull String[] getTypeAdjustmentDeniedPackages() {
+            checkCallerIsSystemOrSystemUiOrShell();
+            return mAssistants.getTypeAdjustmentDeniedPackages();
+        }
+
+        @Override
+        @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+        public void setTypeAdjustmentForPackageState(String pkg, boolean enabled) {
+            checkCallerIsSystemOrSystemUiOrShell();
+            mAssistants.setTypeAdjustmentForPackageState(pkg, enabled);
+
+            handleSavePolicyFile();
+        }
+
+        @Override
         @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
         public boolean appCanBePromoted(String pkg, int uid) {
             checkCallerIsSystemOrSystemUiOrShell();
@@ -6580,6 +6597,14 @@
                         android.Manifest.permission.INTERACT_ACROSS_USERS,
                         "setNotificationListenerAccessGrantedForUser for user " + userId);
             }
+            if (mUmInternal.isVisibleBackgroundFullUser(userId)) {
+                // The main use case for visible background users is the Automotive multi-display
+                // configuration where a passenger can use a secondary display while the driver is
+                // using the main display. NotificationListeners is designed only for the current
+                // user and work profile. We added a condition to prevent visible background users
+                // from updating the data managed within the NotificationListeners object.
+                return;
+            }
             checkNotificationListenerAccess();
             if (granted && listener.flattenToString().length()
                     > NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH) {
@@ -7006,6 +7031,10 @@
                 if (notificationClassification() && adjustments.containsKey(KEY_TYPE)) {
                     if (!mAssistants.isAdjustmentKeyTypeAllowed(adjustments.getInt(KEY_TYPE))) {
                         toRemove.add(potentialKey);
+                    } else if (notificationClassificationUi()
+                            && !mAssistants.isTypeAdjustmentAllowedForPackage(
+                            r.getSbn().getPackageName())) {
+                        toRemove.add(potentialKey);
                     }
                 }
             }
@@ -10500,6 +10529,27 @@
                             mGroupHelper.onNotificationRemoved(r, mNotificationList);
                         }
                     });
+
+                    // Wait 3 seconds so that the app has a chance to cancel/post
+                    // a group summary or children
+                    final NotificationRecord groupSummary = mSummaryByGroupKey.get(r.getGroupKey());
+                    if (groupSummary != null
+                            && !GroupHelper.isAggregatedGroup(groupSummary)
+                            && !groupSummary.getKey().equals(canceledKey)) {
+                        // We only care about app-provided valid group summaries
+                        final String summaryKey = groupSummary.getKey();
+                        mHandler.removeCallbacksAndEqualMessages(summaryKey);
+                        mHandler.postDelayed(() -> {
+                            synchronized (mNotificationLock) {
+                                NotificationRecord summaryRecord = mNotificationsByKey.get(
+                                        summaryKey);
+                                if (summaryRecord != null) {
+                                    mGroupHelper.onGroupedNotificationRemovedWithDelay(
+                                            summaryRecord, mNotificationList, mSummaryByGroupKey);
+                                }
+                            }
+                        }, summaryKey, DELAY_FORCE_REGROUP_TIME);
+                    }
                 } else {
                     mHandler.post(new Runnable() {
                         @Override
@@ -11643,6 +11693,7 @@
         private static final String ATT_DENIED = "denied_adjustments";
         private static final String ATT_ENABLED_TYPES = "enabled_key_types";
         private static final String ATT_NAS_UNSUPPORTED = "unsupported_adjustments";
+        private static final String ATT_TYPES_DENIED_APPS = "types_denied_apps";
 
         private final Object mLock = new Object();
 
@@ -11658,6 +11709,9 @@
         @GuardedBy("mLock")
         private Map<Integer, HashSet<String>> mNasUnsupported = new ArrayMap<>();
 
+        @GuardedBy("mLock")
+        private Set<String> mClassificationTypeDeniedPackages = new ArraySet<>();
+
         protected ComponentName mDefaultFromConfig = null;
 
         @Override
@@ -11857,6 +11911,44 @@
             }
         }
 
+        @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+        protected @NonNull boolean isTypeAdjustmentAllowedForPackage(String pkg) {
+            synchronized (mLock) {
+                if (notificationClassificationUi()) {
+                    return !mClassificationTypeDeniedPackages.contains(pkg);
+                }
+            }
+            return true;
+        }
+
+        @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+        protected @NonNull String[] getTypeAdjustmentDeniedPackages() {
+            synchronized (mLock) {
+                if (notificationClassificationUi()) {
+                    return mClassificationTypeDeniedPackages.toArray(new String[0]);
+                }
+            }
+            return new String[]{};
+        }
+
+        /**
+         * Set whether a particular package can have its notification channels adjusted to have a
+         * different type by NotificationAssistants.
+         */
+        @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+        public void setTypeAdjustmentForPackageState(String pkg, boolean enabled) {
+            if (!notificationClassificationUi()) {
+                return;
+            }
+            synchronized (mLock) {
+                if (enabled) {
+                    mClassificationTypeDeniedPackages.remove(pkg);
+                } else {
+                    mClassificationTypeDeniedPackages.add(pkg);
+                }
+            }
+        }
+
         protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
                 ArrayList<String> keys = new ArrayList<>(records.size());
@@ -11953,8 +12045,10 @@
                             assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel(),
                                     update);
                         }
+                    } catch (DeadObjectException ex) {
+                        Slog.wtf(TAG, "unable to notify assistant (enqueued): " + info, ex);
                     } catch (RemoteException ex) {
-                        Slog.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
+                        Slog.e(TAG, "unable to notify assistant (enqueued): " + info, ex);
                     }
                 }
             }
@@ -12075,19 +12169,21 @@
                     r.getSbn(),
                     r.getNotificationType(),
                     true /* sameUserOnly */,
-                    (assistant, sbnToPost) -> {
+                    (info, sbnToPost) -> {
                         try {
                             if (android.app.Flags.noSbnholder()) {
-                                assistant.onNotificationSnoozedUntilContextFull(
+                                info.onNotificationSnoozedUntilContextFull(
                                         sbnToPost, snoozeCriterionId);
                             } else {
                                 final StatusBarNotificationHolder sbnHolder =
                                         new StatusBarNotificationHolder(sbnToPost);
-                                assistant.onNotificationSnoozedUntilContext(
+                                info.onNotificationSnoozedUntilContext(
                                         sbnHolder, snoozeCriterionId);
                             }
+                        } catch (DeadObjectException ex) {
+                            Slog.wtf(TAG, "unable to notify assistant (snoozed): " + info, ex);
                         } catch (RemoteException ex) {
-                            Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
+                            Slog.e(TAG, "unable to notify assistant (snoozed): " + info, ex);
                         }
                     });
         }
@@ -12315,6 +12411,12 @@
                 out.attribute(null, ATT_TYPES,
                         TextUtils.join(",", mAllowedAdjustmentKeyTypes));
                 out.endTag(null, ATT_ENABLED_TYPES);
+                if (notificationClassificationUi()) {
+                    out.startTag(null, ATT_TYPES_DENIED_APPS);
+                    out.attribute(null, ATT_TYPES,
+                            TextUtils.join(",", mClassificationTypeDeniedPackages));
+                    out.endTag(null, ATT_TYPES_DENIED_APPS);
+                }
             }
         }
 
@@ -12346,6 +12448,14 @@
                         }
                     }
                 }
+            } else if (notificationClassificationUi() && ATT_TYPES_DENIED_APPS.equals(tag)) {
+                final String apps = XmlUtils.readStringAttribute(parser, ATT_TYPES);
+                synchronized (mLock) {
+                    mClassificationTypeDeniedPackages.clear();
+                    if (!TextUtils.isEmpty(apps)) {
+                        mClassificationTypeDeniedPackages.addAll(Arrays.asList(apps.split(",")));
+                    }
+                }
             }
         }
 
@@ -12644,6 +12754,20 @@
         }
 
         @Override
+        public void onUserUnlocked(int user) {
+            if (mUmInternal.isVisibleBackgroundFullUser(user)) {
+                // The main use case for visible background users is the Automotive
+                // multi-display configuration where a passenger can use a secondary
+                // display while the driver is using the main display.
+                // NotificationListeners is designed only for the current user and work
+                // profile. We added a condition to prevent visible background users from
+                // updating the data managed within the NotificationListeners object.
+                return;
+            }
+            super.onUserUnlocked(user);
+        }
+
+        @Override
         protected boolean allowRebindForParentUser() {
             return true;
         }
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 81dc38a..dc173b1 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -1941,7 +1941,17 @@
     @Nullable
     public Policy getNotificationPolicy(UserHandle user) {
         synchronized (mConfigLock) {
-            return getNotificationPolicy(getConfigLocked(user));
+            if (Flags.modesMultiuser()) {
+                // Return a fallback (default) policy for users without a zen config.
+                // Note that zen updates (setPolicy, setFilter) won't be applied, so this is mostly
+                // about preventing NPEs for careless callers.
+                ZenModeConfig config = getConfigLocked(user);
+                return config != null
+                        ? getNotificationPolicy(config)
+                        : getNotificationPolicy(mDefaultConfig);
+            } else {
+                return getNotificationPolicy(getConfigLocked(user));
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/BackgroundInstallControlCallbackHelper.java b/services/core/java/com/android/server/pm/BackgroundInstallControlCallbackHelper.java
index 27c4e9d..bc0fc2b 100644
--- a/services/core/java/com/android/server/pm/BackgroundInstallControlCallbackHelper.java
+++ b/services/core/java/com/android/server/pm/BackgroundInstallControlCallbackHelper.java
@@ -33,9 +33,10 @@
 
 public class BackgroundInstallControlCallbackHelper {
 
-    @VisibleForTesting static final String FLAGGED_PACKAGE_NAME_KEY = "packageName";
-    @VisibleForTesting static final String FLAGGED_USER_ID_KEY = "userId";
-    @VisibleForTesting static final String INSTALL_EVENT_TYPE_KEY = "installEventType";
+    public static final String FLAGGED_PACKAGE_NAME_KEY = "packageName";
+    public static final String FLAGGED_USER_ID_KEY = "userId";
+    public static final String INSTALL_EVENT_TYPE_KEY = "installEventType";
+
     private static final String TAG = "BackgroundInstallControlCallbackHelper";
 
     private final Handler mHandler;
diff --git a/services/core/java/com/android/server/pm/InstallDependencyHelper.java b/services/core/java/com/android/server/pm/InstallDependencyHelper.java
index 527d680..13aab11 100644
--- a/services/core/java/com/android/server/pm/InstallDependencyHelper.java
+++ b/services/core/java/com/android/server/pm/InstallDependencyHelper.java
@@ -16,13 +16,16 @@
 
 package com.android.server.pm;
 
+import static android.content.pm.PackageInstaller.ACTION_INSTALL_DEPENDENCY;
 import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
 import static android.os.Process.SYSTEM_UID;
 
 import android.annotation.NonNull;
+import android.app.role.RoleManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.dependencyinstaller.DependencyInstallerCallback;
@@ -33,12 +36,15 @@
 import android.os.OutcomeReceiver;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.ArraySet;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.infra.AndroidFuture;
 import com.android.internal.infra.ServiceConnector;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
@@ -48,22 +54,27 @@
 public class InstallDependencyHelper {
     private static final String TAG = InstallDependencyHelper.class.getSimpleName();
     private static final boolean DEBUG = true;
-    private static final String ACTION_INSTALL_DEPENDENCY =
-            "android.intent.action.INSTALL_DEPENDENCY";
+    private static final String ROLE_SYSTEM_DEPENDENCY_INSTALLER =
+            "android.app.role.SYSTEM_DEPENDENCY_INSTALLER";
     // The maximum amount of time to wait before the system unbinds from the verifier.
     private static final long UNBIND_TIMEOUT_MILLIS = TimeUnit.HOURS.toMillis(6);
     private static final long REQUEST_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(1);
 
-    private final SharedLibrariesImpl mSharedLibraries;
     private final Context mContext;
+    private final SharedLibrariesImpl mSharedLibraries;
+    private final PackageInstallerService mPackageInstallerService;
     private final Object mRemoteServiceLock = new Object();
+    @GuardedBy("mTrackers")
+    private final List<DependencyInstallTracker> mTrackers = new ArrayList<>();
 
     @GuardedBy("mRemoteServiceLock")
     private ServiceConnector<IDependencyInstallerService> mRemoteService = null;
 
-    InstallDependencyHelper(Context context, SharedLibrariesImpl sharedLibraries) {
+    InstallDependencyHelper(Context context, SharedLibrariesImpl sharedLibraries,
+            PackageInstallerService packageInstallerService) {
         mContext = context;
         mSharedLibraries = sharedLibraries;
+        mPackageInstallerService = packageInstallerService;
     }
 
     void resolveLibraryDependenciesIfNeeded(PackageLite pkg, Computer snapshot, int userId,
@@ -86,7 +97,7 @@
 
         if (missing.isEmpty()) {
             if (DEBUG) {
-                Slog.i(TAG, "No missing dependency for " + pkg);
+                Slog.d(TAG, "No missing dependency for " + pkg);
             }
             // No need for dependency resolution. Move to installation directly.
             callback.onResult(null);
@@ -98,19 +109,8 @@
             return;
         }
 
-        IDependencyInstallerCallback serviceCallback = new IDependencyInstallerCallback.Stub() {
-            @Override
-            public void onAllDependenciesResolved(int[] sessionIds) throws RemoteException {
-                // TODO(b/372862145): Implement waiting for sessions to finish installation
-                callback.onResult(null);
-            }
-
-            @Override
-            public void onFailureToResolveAllDependencies() throws RemoteException {
-                onError(callback, "Failed to resolve all dependencies automatically");
-            }
-        };
-
+        IDependencyInstallerCallback serviceCallback =
+                new DependencyInstallerCallbackCallOnce(handler, callback, userId);
         boolean scheduleSuccess;
         synchronized (mRemoteServiceLock) {
             scheduleSuccess = mRemoteService.run(service -> {
@@ -123,10 +123,28 @@
         }
     }
 
-    private void onError(CallOnceProxy callback, String msg) {
+    void notifySessionComplete(int sessionId, boolean success) {
+        if (DEBUG) {
+            Slog.d(TAG, "Session complete for " + sessionId + " result: " + success);
+        }
+        synchronized (mTrackers) {
+            List<DependencyInstallTracker> completedTrackers = new ArrayList<>();
+            for (DependencyInstallTracker tracker: mTrackers) {
+                if (!tracker.onSessionComplete(sessionId, success)) {
+                    completedTrackers.add(tracker);
+                }
+            }
+            mTrackers.removeAll(completedTrackers);
+        }
+    }
+
+    private static void onError(CallOnceProxy callback, String msg) {
         PackageManagerException pe = new PackageManagerException(
                 INSTALL_FAILED_MISSING_SHARED_LIBRARY, msg);
         callback.onError(pe);
+        if (DEBUG) {
+            Slog.i(TAG, "Orig session error: " + msg);
+        }
     }
 
     private boolean bindToDependencyInstallerIfNeeded(int userId, Handler handler,
@@ -140,8 +158,20 @@
             }
         }
 
+        RoleManager roleManager = mContext.getSystemService(RoleManager.class);
+        if (roleManager == null) {
+            Slog.w(TAG, "Cannot find RoleManager system service");
+            return false;
+        }
+        List<String> holders = roleManager.getRoleHoldersAsUser(
+                ROLE_SYSTEM_DEPENDENCY_INSTALLER, UserHandle.of(userId));
+        if (holders.isEmpty()) {
+            Slog.w(TAG, "No holders of ROLE_SYSTEM_DEPENDENCY_INSTALLER found");
+            return false;
+        }
+
         Intent serviceIntent = new Intent(ACTION_INSTALL_DEPENDENCY);
-        // TODO(b/372862145): Use RoleManager to find the package name
+        serviceIntent.setPackage(holders.getFirst());
         List<ResolveInfo> resolvedIntents = snapshot.queryIntentServicesInternal(
                 serviceIntent, /*resolvedType=*/ null, /*flags=*/0,
                 userId, SYSTEM_UID, Process.INVALID_PID,
@@ -151,7 +181,6 @@
             return false;
         }
 
-
         ResolveInfo resolveInfo = resolvedIntents.getFirst();
         ComponentName componentName = resolveInfo.getComponentInfo().getComponentName();
         serviceIntent.setComponent(componentName);
@@ -253,4 +282,185 @@
             }
         }
     }
+
+    /**
+     * Ensure we call one of the outcomes only once, on the right handler.
+     *
+     * Repeated calls will be no-op.
+     */
+    private class DependencyInstallerCallbackCallOnce extends IDependencyInstallerCallback.Stub {
+
+        private final Handler mHandler;
+        private final CallOnceProxy mCallback;
+        private final int mUserId;
+
+        @GuardedBy("this")
+        private boolean mDependencyInstallerCallbackInvoked = false;
+
+        DependencyInstallerCallbackCallOnce(Handler handler, CallOnceProxy callback, int userId) {
+            mHandler = handler;
+            mCallback = callback;
+            mUserId = userId;
+        }
+
+        @Override
+        public void onAllDependenciesResolved(int[] sessionIds) throws RemoteException {
+            synchronized (this) {
+                if (mDependencyInstallerCallbackInvoked) {
+                    throw new IllegalStateException(
+                            "Callback is being or has been already processed");
+                }
+                mDependencyInstallerCallbackInvoked = true;
+            }
+
+
+            if (DEBUG) {
+                Slog.d(TAG, "onAllDependenciesResolved started");
+            }
+
+            // Before creating any tracker, validate the arguments
+            ArraySet<Integer> validSessionIds = validateSessionIds(sessionIds);
+
+            if (validSessionIds.isEmpty()) {
+                mCallback.onResult(null);
+                return;
+            }
+
+            // Create a tracker now if there are any pending sessions remaining.
+            DependencyInstallTracker tracker = new DependencyInstallTracker(
+                    mCallback, validSessionIds);
+            synchronized (mTrackers) {
+                mTrackers.add(tracker);
+            }
+
+            // By the time the tracker was created, some of the sessions in validSessionIds
+            // could have finished. Avoid waiting for them indefinitely.
+            for (int sessionId : validSessionIds) {
+                SessionInfo sessionInfo = mPackageInstallerService.getSessionInfo(sessionId);
+
+                // Don't wait for sessions that finished already
+                if (sessionInfo == null) {
+                    notifySessionComplete(sessionId, /*success=*/ true);
+                }
+            }
+        }
+
+        @Override
+        public void onFailureToResolveAllDependencies() throws RemoteException {
+            synchronized (this) {
+                if (mDependencyInstallerCallbackInvoked) {
+                    throw new IllegalStateException(
+                            "Callback is being or has been already processed");
+                }
+                mDependencyInstallerCallbackInvoked = true;
+            }
+            onError(mCallback, "Failed to resolve all dependencies automatically");
+        }
+
+        private ArraySet<Integer> validateSessionIds(int[] sessionIds) {
+            // Before creating any tracker, validate the arguments
+            ArraySet<Integer> validSessionIds = new ArraySet<>();
+
+            List<SessionInfo> historicalSessions = null;
+            for (int i = 0; i < sessionIds.length; i++) {
+                int sessionId = sessionIds[i];
+                SessionInfo sessionInfo = mPackageInstallerService.getSessionInfo(sessionId);
+
+                // Continue waiting if session exists and hasn't passed or failed yet.
+                if (sessionInfo != null) {
+                    if (sessionInfo.isSessionFailed) {
+                        throwValidationError("Session already finished: " + sessionId);
+                    }
+
+                    // Wait for session to finish install if it's not already successful.
+                    if (!sessionInfo.isSessionApplied) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "onAllDependenciesResolved pending session: " + sessionId);
+                        }
+                        validSessionIds.add(sessionId);
+                    }
+
+                    // An applied session found. No need to check historical session anymore.
+                    continue;
+                }
+
+                if (DEBUG) {
+                    Slog.d(TAG, "onAllDependenciesResolved cleaning up finished"
+                            + " session: " + sessionId);
+                }
+
+                if (historicalSessions == null) {
+                    historicalSessions = mPackageInstallerService.getHistoricalSessions(
+                            mUserId).getList();
+                }
+
+                sessionInfo = historicalSessions.stream().filter(
+                        s -> s.sessionId == sessionId).findFirst().orElse(null);
+
+                if (sessionInfo == null) {
+                    throwValidationError("Failed to find session: " + sessionId);
+                }
+
+                // Historical session must have been successful, otherwise throw IAE.
+                if (!sessionInfo.isSessionApplied) {
+                    throwValidationError("Session already finished: " + sessionId);
+                }
+            }
+
+            return validSessionIds;
+        }
+
+        private void throwValidationError(String msg) {
+            // Allow client to invoke callback again.
+            synchronized (this) {
+                mDependencyInstallerCallbackInvoked = false;
+            }
+            throw new IllegalArgumentException(msg);
+        }
+    }
+
+    /**
+     * Tracks a list of session ids against a particular callback.
+     *
+     * If all the sessions completes successfully, it invokes the positive flow. If any of the
+     * sessions fails, it invokes the failure flow immediately.
+     */
+    // TODO(b/372862145): Determine and add support for rebooting while dependency is being resolved
+    private static class DependencyInstallTracker {
+        private final CallOnceProxy mCallback;
+        @GuardedBy("this")
+        private final ArraySet<Integer> mPendingSessionIds;
+
+        DependencyInstallTracker(CallOnceProxy callback, ArraySet<Integer> pendingSessionIds) {
+            mCallback = callback;
+            mPendingSessionIds = pendingSessionIds;
+        }
+
+        /**
+         * Process a session complete event.
+         *
+         * Returns true if we still need to continue tracking.
+         */
+        public boolean onSessionComplete(int sessionId, boolean success) {
+            synchronized (this) {
+                if (!mPendingSessionIds.contains(sessionId)) {
+                    // This had no impact on tracker, so continue tracking
+                    return true;
+                }
+
+                if (!success) {
+                    // If one of the dependency fails, the orig session would fail too.
+                    onError(mCallback, "Failed to install all dependencies");
+                    return false; // No point in tracking anymore
+                }
+
+                mPendingSessionIds.remove(sessionId);
+                if (mPendingSessionIds.isEmpty()) {
+                    mCallback.onResult(null);
+                    return false; // Nothing to track anymore
+                }
+                return true; // Keep on tracking
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java
index c66a9e9..0930299 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelper.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
 import android.util.ArraySet;
 import android.util.Pair;
 
@@ -28,8 +29,6 @@
 
 import java.io.File;
 
-
-
 // TODO: Move to .parsing sub-package
 @VisibleForTesting
 public interface PackageAbiHelper {
@@ -79,6 +78,23 @@
             AndroidPackage scannedPackage);
 
     /**
+     * Checks alignment of APK and native libraries for 16KB device
+     *
+     * @param pkg AndroidPackage for which alignment check is being done
+     * @param libraryRoot directory for libraries
+     * @param nativeLibraryRootRequiresIsa use isa
+     * @param cpuAbiOverride ABI override mentioned in package
+     * @return {ApplicationInfo.PageSizeAppCompat} if successful or error code
+     *     which suggests undefined mode
+     */
+    @ApplicationInfo.PageSizeAppCompatFlags
+    int checkPackageAlignment(
+            AndroidPackage pkg,
+            String libraryRoot,
+            boolean nativeLibraryRootRequiresIsa,
+            String cpuAbiOverride);
+
+    /**
      * The native library paths and related properties that should be set on a
      * {@link ParsedPackage}.
      */
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index 9db4d33..7229f07 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -29,6 +29,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.Flags;
 import android.content.pm.PackageManager;
 import android.os.Build;
@@ -625,4 +626,22 @@
         }
         return adjustedAbi;
     }
+
+    @Override
+    public int checkPackageAlignment(
+            AndroidPackage pkg,
+            String libraryRoot,
+            boolean nativeLibraryRootRequiresIsa,
+            String abiOverride) {
+        NativeLibraryHelper.Handle handle = null;
+        try {
+            handle = AndroidPackageUtils.createNativeLibraryHandle(pkg);
+            return NativeLibraryHelper.checkAlignmentForCompatMode(
+                            handle, libraryRoot, nativeLibraryRootRequiresIsa, abiOverride);
+        } catch (IOException e) {
+            Slog.e(PackageManagerService.TAG, "Failed to check alignment of package : "
+                    + pkg.getPackageName());
+            return ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index a4152a7..ceb9314 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -327,7 +327,7 @@
                 context, mInstallThread.getLooper(), new AppStateHelper(context));
         mPackageArchiver = new PackageArchiver(mContext, mPm);
         mInstallDependencyHelper = new InstallDependencyHelper(mContext,
-                mPm.mInjector.getSharedLibrariesImpl());
+                mPm.mInjector.getSharedLibrariesImpl(), this);
 
         LocalServices.getService(SystemServiceManager.class).startService(
                 new Lifecycle(context, this));
@@ -337,6 +337,10 @@
         return mStagingManager;
     }
 
+    InstallDependencyHelper getInstallDependencyHelper() {
+        return mInstallDependencyHelper;
+    }
+
     boolean okToSendBroadcasts()  {
         return mOkToSendBroadcasts;
     }
@@ -2325,6 +2329,8 @@
                             }
                         }
 
+                        mInstallDependencyHelper.notifySessionComplete(session.sessionId, success);
+
                         final File appIconFile = buildAppIconFile(session.sessionId);
                         if (appIconFile.exists()) {
                             appIconFile.delete();
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 8f8802e..891d66a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -61,6 +61,7 @@
 
 import android.Manifest;
 import android.annotation.AnyThread;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -188,6 +189,7 @@
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
 import com.android.server.LocalServices;
+import com.android.server.art.ArtManagedInstallFileHelper;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.pkg.AndroidPackage;
@@ -852,7 +854,11 @@
             if (file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false;
             if (file.getName().endsWith(V4Signature.EXT)) return false;
             if (isAppMetadata(file)) return false;
-            if (DexMetadataHelper.isDexMetadataFile(file)) return false;
+            if (com.android.art.flags.Flags.artServiceV3()) {
+                if (ArtManagedInstallFileHelper.isArtManaged(file.getPath())) return false;
+            } else {
+                if (DexMetadataHelper.isDexMetadataFile(file)) return false;
+            }
             if (VerityUtils.isFsveritySignatureFile(file)) return false;
             if (ApkChecksums.isDigestOrDigestSignatureFile(file)) return false;
             return true;
@@ -876,6 +882,13 @@
             return true;
         }
     };
+    private static final FileFilter sArtManagedFilter = new FileFilter() {
+        @Override
+        public boolean accept(File file) {
+            return !file.isDirectory() && com.android.art.flags.Flags.artServiceV3()
+                    && ArtManagedInstallFileHelper.isArtManaged(file.getPath());
+        }
+    };
 
     static boolean isDataLoaderInstallation(SessionParams params) {
         return params.dataLoaderParams != null;
@@ -1607,6 +1620,19 @@
     }
 
     @GuardedBy("mLock")
+    private List<String> getArtManagedFilePathsLocked() {
+        String[] names = getNamesLocked();
+        ArrayList<String> result = new ArrayList<>(names.length);
+        for (String name : names) {
+            File file = new File(stageDir, name);
+            if (sArtManagedFilter.accept(file)) {
+                result.add(file.getPath());
+            }
+        }
+        return result;
+    }
+
+    @GuardedBy("mLock")
     private void enableFsVerityToAddedApksWithIdsig() throws PackageManagerException {
         try {
             List<File> files = getAddedApksLocked();
@@ -3453,7 +3479,7 @@
         }
 
         final File targetFile = new File(stageDir, targetName);
-        resolveAndStageFileLocked(addedFile, targetFile, null);
+        resolveAndStageFileLocked(addedFile, targetFile, null, List.of() /* artManagedFilePaths */);
         mResolvedBaseFile = targetFile;
 
         // Populate package name of the apex session
@@ -3546,6 +3572,7 @@
                     TextUtils.formatSimple("Session: %d. No packages staged in %s", sessionId,
                           stageDir.getAbsolutePath()));
         }
+        final List<String> artManagedFilePaths = getArtManagedFilePathsLocked();
 
         // Verify that all staged packages are internally consistent
         final ArraySet<String> stagedSplits = new ArraySet<>();
@@ -3602,7 +3629,8 @@
             final File targetFile = new File(stageDir, targetName);
             if (!isArchivedInstallation()) {
                 final File sourceFile = new File(apk.getPath());
-                resolveAndStageFileLocked(sourceFile, targetFile, apk.getSplitName());
+                resolveAndStageFileLocked(
+                        sourceFile, targetFile, apk.getSplitName(), artManagedFilePaths);
             }
 
             // Base is coming from session
@@ -3763,7 +3791,7 @@
             // Inherit base if not overridden.
             if (mResolvedBaseFile == null) {
                 mResolvedBaseFile = new File(appInfo.getBaseCodePath());
-                inheritFileLocked(mResolvedBaseFile);
+                inheritFileLocked(mResolvedBaseFile, artManagedFilePaths);
                 // Collect the requiredSplitTypes from base
                 CollectionUtils.addAll(requiredSplitTypes, existing.getBaseRequiredSplitTypes());
             } else if ((params.installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
@@ -3782,7 +3810,7 @@
                     final boolean splitRemoved = removeSplitList.contains(splitName);
                     final boolean splitReplaced = stagedSplits.contains(splitName);
                     if (!splitReplaced && !splitRemoved) {
-                        inheritFileLocked(splitFile);
+                        inheritFileLocked(splitFile, artManagedFilePaths);
                         // Collect the requiredSplitTypes and staged splitTypes from splits
                         CollectionUtils.addAll(requiredSplitTypes,
                                 existing.getRequiredSplitTypes()[i]);
@@ -3968,6 +3996,23 @@
                 DexMetadataHelper.isFsVerityRequired());
     }
 
+    @FlaggedApi(com.android.art.flags.Flags.FLAG_ART_SERVICE_V3)
+    @GuardedBy("mLock")
+    private void maybeStageArtManagedInstallFilesLocked(File origFile, File targetFile,
+            List<String> artManagedFilePaths) throws PackageManagerException {
+        for (String path : ArtManagedInstallFileHelper.filterPathsForApk(
+                     artManagedFilePaths, origFile.getPath())) {
+            File artManagedFile = new File(path);
+            if (!FileUtils.isValidExtFilename(artManagedFile.getName())) {
+                throw new PackageManagerException(
+                        INSTALL_FAILED_INVALID_APK, "Invalid filename: " + artManagedFile);
+            }
+            File targetArtManagedFile = new File(
+                    ArtManagedInstallFileHelper.getTargetPathForApk(path, targetFile.getPath()));
+            stageFileLocked(artManagedFile, targetArtManagedFile);
+        }
+    }
+
     private IncrementalFileStorages getIncrementalFileStorages() {
         synchronized (mLock) {
             return mIncrementalFileStorages;
@@ -4065,8 +4110,8 @@
     }
 
     @GuardedBy("mLock")
-    private void resolveAndStageFileLocked(File origFile, File targetFile, String splitName)
-            throws PackageManagerException {
+    private void resolveAndStageFileLocked(File origFile, File targetFile, String splitName,
+            List<String> artManagedFilePaths) throws PackageManagerException {
         stageFileLocked(origFile, targetFile);
 
         // Stage APK's fs-verity signature if present.
@@ -4077,8 +4122,13 @@
                 && VerityUtils.isFsVeritySupported()) {
             maybeStageV4SignatureLocked(origFile, targetFile);
         }
-        // Stage dex metadata (.dm) and corresponding fs-verity signature if present.
-        maybeStageDexMetadataLocked(origFile, targetFile);
+        // Stage ART managed install files (e.g., dex metadata (.dm)) and corresponding fs-verity
+        // signature if present.
+        if (com.android.art.flags.Flags.artServiceV3()) {
+            maybeStageArtManagedInstallFilesLocked(origFile, targetFile, artManagedFilePaths);
+        } else {
+            maybeStageDexMetadataLocked(origFile, targetFile);
+        }
         // Stage checksums (.digests) if present.
         maybeStageDigestsLocked(origFile, targetFile, splitName);
     }
@@ -4103,7 +4153,7 @@
     }
 
     @GuardedBy("mLock")
-    private void inheritFileLocked(File origFile) {
+    private void inheritFileLocked(File origFile, List<String> artManagedFilePaths) {
         mResolvedInheritedFiles.add(origFile);
 
         maybeInheritFsveritySignatureLocked(origFile);
@@ -4111,12 +4161,20 @@
             maybeInheritV4SignatureLocked(origFile);
         }
 
-        // Inherit the dex metadata if present.
-        final File dexMetadataFile =
-                DexMetadataHelper.findDexMetadataForFile(origFile);
-        if (dexMetadataFile != null) {
-            mResolvedInheritedFiles.add(dexMetadataFile);
-            maybeInheritFsveritySignatureLocked(dexMetadataFile);
+        // Inherit ART managed install files (e.g., dex metadata (.dm)) if present.
+        if (com.android.art.flags.Flags.artServiceV3()) {
+            for (String path : ArtManagedInstallFileHelper.filterPathsForApk(
+                         artManagedFilePaths, origFile.getPath())) {
+                File artManagedFile = new File(path);
+                mResolvedInheritedFiles.add(artManagedFile);
+                maybeInheritFsveritySignatureLocked(artManagedFile);
+            }
+        } else {
+            final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(origFile);
+            if (dexMetadataFile != null) {
+                mResolvedInheritedFiles.add(dexMetadataFile);
+                maybeInheritFsveritySignatureLocked(dexMetadataFile);
+            }
         }
         // Inherit the digests if present.
         final File digestsFile = ApkChecksums.findDigestsForFile(origFile);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 807445e..ab26f02 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -5874,6 +5874,67 @@
                     userId, callingPackage);
         }
 
+        @Override
+        public void setPageSizeAppCompatFlagsSettingsOverride(String packageName, boolean enabled) {
+            final int callingUid = Binder.getCallingUid();
+            final int callingAppId = UserHandle.getAppId(callingUid);
+
+            if (!PackageManagerServiceUtils.isSystemOrRoot(callingAppId)) {
+                throw new SecurityException("Caller must be the system or root.");
+            }
+
+            int settingsMode = enabled
+                    ? ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_SETTINGS_OVERRIDE_ENABLED
+                    : ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_SETTINGS_OVERRIDE_DISABLED;
+            PackageStateMutator.Result result =
+                    commitPackageStateMutation(
+                            null,
+                            packageName,
+                            packageState ->
+                                    packageState
+                                            .setPageSizeAppCompatFlags(settingsMode));
+            if (result.isSpecificPackageNull()) {
+                throw new IllegalArgumentException("Unknown package: " + packageName);
+            }
+            scheduleWriteSettings();
+        }
+
+        @Override
+        public boolean isPageSizeCompatEnabled(String packageName) {
+            final int callingUid = Binder.getCallingUid();
+            final int callingAppId = UserHandle.getAppId(callingUid);
+            final int userId = UserHandle.getCallingUserId();
+
+            if (!PackageManagerServiceUtils.isSystemOrRoot(callingAppId)) {
+                throw new SecurityException("Caller must be the system or root.");
+            }
+
+            PackageStateInternal packageState =
+                    snapshotComputer().getPackageStateForInstalledAndFiltered(
+                            packageName, callingUid, userId);
+
+            return packageState == null ? false : packageState.isPageSizeAppCompatEnabled();
+        }
+
+        @Override
+        public String getPageSizeCompatWarningMessage(String packageName) {
+            final int callingUid = Binder.getCallingUid();
+            final int callingAppId = UserHandle.getAppId(callingUid);
+            final int userId = UserHandle.getCallingUserId();
+
+            if (!PackageManagerServiceUtils.isSystemOrRoot(callingAppId)) {
+                throw new SecurityException("Caller must be the system or root.");
+            }
+
+            PackageStateInternal packageState =
+                    snapshotComputer().getPackageStateForInstalledAndFiltered(
+                            packageName, callingUid, userId);
+
+            return packageState == null
+                    ? null
+                    : packageState.getPageSizeCompatWarningMessage(mContext);
+        }
+
         @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_USERS)
         @Override
         public boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden,
@@ -6578,6 +6639,20 @@
         }
 
         @Override
+        @NonNull
+        public List<String> getAllApexDirectories() {
+            PackageManagerServiceUtils.enforceSystemOrRoot(
+                    "getAllApexDirectories can only be called by system or root");
+            List<String> apexDirectories = new ArrayList<>();
+            List<ApexManager.ActiveApexInfo> apexes = mApexManager.getActiveApexInfos();
+            for (int i = 0; i < apexes.size(); i++) {
+                ApexManager.ActiveApexInfo apex = apexes.get(i);
+                apexDirectories.add(apex.apexDirectory.getAbsolutePath());
+            }
+            return apexDirectories;
+        }
+
+        @Override
         public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
                 throws RemoteException {
             try {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index e339cec..aa235c2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -3601,7 +3601,7 @@
                     break;
                 case "--disable-auto-install-dependencies":
                     if (Flags.sdkDependencyInstaller()) {
-                        sessionParams.setEnableAutoInstallDependencies(false);
+                        sessionParams.setAutoInstallDependenciesEnabled(false);
                     } else {
                         throw new IllegalArgumentException("Unknown option " + opt);
                     }
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 9428de7..fb16b86 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -27,6 +27,7 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.SharedLibraryInfo;
@@ -221,6 +222,8 @@
     /** @see PackageState#getCategoryOverride() */
     private int categoryOverride = ApplicationInfo.CATEGORY_UNDEFINED;
 
+    private int mPageSizeAppCompatFlags = ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED;
+
     @NonNull
     private final PackageStateUnserialized pkgState = new PackageStateUnserialized(this);
 
@@ -863,6 +866,8 @@
         }
 
         copyMimeGroups(other.mimeGroups);
+        mPageSizeAppCompatFlags = other.mPageSizeAppCompatFlags;
+
         pkgState.updateFrom(other.pkgState);
         onChanged();
     }
@@ -1617,6 +1622,34 @@
         return this;
     }
 
+    /**
+     * @see Set page size app compat mode.
+     */
+    public PackageSetting setPageSizeAppCompatFlags(int mode) {
+        if (mode < 0 || mode >= ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_MAX) {
+            throw new IllegalArgumentException("Invalid page size compat mode specified");
+        }
+
+        // OR assignment is used here to avoid overriding the mode set by the manifest.
+        this.mPageSizeAppCompatFlags |= mode;
+
+        // Only one bit of the following can be set at same time. Both are needed to detect app
+        // compat 'disabled' state from settings vs bit was never set.
+        if (ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_SETTINGS_OVERRIDE_ENABLED == mode) {
+            this.mPageSizeAppCompatFlags &=
+                    ~ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_SETTINGS_OVERRIDE_DISABLED;
+        } else if (ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_SETTINGS_OVERRIDE_DISABLED == mode) {
+            this.mPageSizeAppCompatFlags &=
+                    ~ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_SETTINGS_OVERRIDE_ENABLED;
+        }
+        onChanged();
+        return this;
+    }
+
+    public int getPageSizeAppCompatFlags() {
+        return mPageSizeAppCompatFlags;
+    }
+
     public PackageSetting setLegacyNativeLibraryPath(
             String legacyNativeLibraryPathString) {
         this.legacyNativeLibraryPath = legacyNativeLibraryPathString;
@@ -1787,6 +1820,63 @@
         return getBoolean(Booleans.SCANNED_AS_STOPPED_SYSTEM_APP);
     }
 
+    /** Returns true if ELF files will be loaded in Page size compatibility mode */
+    @Override
+    public boolean isPageSizeAppCompatEnabled() {
+        // If manifest or settings has disabled the compat mode, don't run app in compat mode.
+        boolean manifestOverrideDisabled = (mPageSizeAppCompatFlags
+                &  ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_DISABLED) != 0;
+        boolean settingsOverrideDisabled = (mPageSizeAppCompatFlags
+                &  ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_SETTINGS_OVERRIDE_DISABLED) != 0;
+        if (manifestOverrideDisabled || settingsOverrideDisabled) {
+            return false;
+        }
+
+        int mask =
+                ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_ELF_NOT_ALIGNED
+                        | ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_ENABLED
+                        | ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_SETTINGS_OVERRIDE_ENABLED;
+        return (mPageSizeAppCompatFlags & mask) != 0;
+    }
+
+    /**
+     * Returns dialog string based on alignment of uncompressed shared libs inside the APK and ELF
+     * alignment.
+     */
+    @Override
+    public String getPageSizeCompatWarningMessage(Context context) {
+        boolean manifestOverrideEnabled =  (mPageSizeAppCompatFlags
+                & ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_ENABLED) != 0;
+        boolean settingsOverrideEnabled =  (mPageSizeAppCompatFlags
+                & ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_ENABLED) != 0;
+        if (manifestOverrideEnabled || settingsOverrideEnabled) {
+            return null;
+        }
+
+        boolean uncompressedLibsNotAligned = (mPageSizeAppCompatFlags
+                & ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_UNCOMPRESSED_LIBS_NOT_ALIGNED) != 0;
+        boolean elfNotAligned = (mPageSizeAppCompatFlags
+                & ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_ELF_NOT_ALIGNED) != 0;
+
+        if (uncompressedLibsNotAligned && elfNotAligned) {
+            return context.getText(
+                            com.android.internal.R.string.page_size_compat_apk_and_elf_warning)
+                    .toString();
+        }
+
+        if (uncompressedLibsNotAligned) {
+            return context.getText(com.android.internal.R.string.page_size_compat_apk_warning)
+                    .toString();
+        }
+
+        if (elfNotAligned) {
+            return context.getText(com.android.internal.R.string.page_size_compat_elf_warning)
+                    .toString();
+        }
+
+        return null;
+    }
+
 
 
     // Code below generated by codegen v1.0.23.
@@ -1952,7 +2042,6 @@
     @Deprecated
     private void __metadata() {}
 
-
     //@formatter:on
     // End of generated code
 
diff --git a/services/core/java/com/android/server/pm/SaferIntentUtils.java b/services/core/java/com/android/server/pm/SaferIntentUtils.java
index bc36fab..854e142 100644
--- a/services/core/java/com/android/server/pm/SaferIntentUtils.java
+++ b/services/core/java/com/android/server/pm/SaferIntentUtils.java
@@ -26,6 +26,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.compat.annotation.ChangeId;
+import android.compat.annotation.Disabled;
 import android.compat.annotation.EnabledAfter;
 import android.compat.annotation.Overridable;
 import android.content.Intent;
@@ -88,6 +89,22 @@
     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
     private static final long IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS = 229362273;
 
+    /**
+     * Intents sent from apps enabling this feature will stop resolving to components with
+     * non matching intent filters, even when explicitly setting a component name, unless the
+     * target components are in the same app as the calling app.
+     * <p>
+     * When an app registers an exported component in its manifest and adds &lt;intent-filter&gt;s,
+     * the component can be started by any intent - even those that do not match the intent filter.
+     * This has proven to be something that many developers find counterintuitive.
+     * Without checking the intent when the component is started, in some circumstances this can
+     * allow 3P apps to trigger internal-only functionality.
+     */
+    @ChangeId
+    @Overridable
+    @Disabled
+    private static final long ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS = 161252188;
+
     @Nullable
     private static ParsedMainComponent infoToComponent(
             ComponentInfo info, ComponentResolverApi resolver, boolean isReceiver) {
@@ -249,6 +266,20 @@
      */
     public static void enforceIntentFilterMatching(
             IntentArgs args, List<ResolveInfo> resolveInfos) {
+        // Switch to the new intent matching logic if the feature flag is enabled.
+        // Otherwise, use the existing AppCompat based implementation.
+        if (Flags.enableIntentMatchingFlags()) {
+            enforceIntentFilterMatchingWithIntentMatchingFlags(args, resolveInfos);
+        } else {
+            enforceIntentFilterMatchingWithAppCompat(args, resolveInfos);
+        }
+    }
+
+    /**
+     * This version of the method is implemented in Android B and uses "IntentMatchingFlags"
+     */
+    private static void enforceIntentFilterMatchingWithIntentMatchingFlags(
+                IntentArgs args, List<ResolveInfo> resolveInfos) {
         if (DISABLE_ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS.get()) return;
 
         // Do not enforce filter matching when the caller is system or root
@@ -339,6 +370,97 @@
     }
 
     /**
+     * This version of the method is implemented in Android V and uses "AppCompat"
+     */
+    private static void enforceIntentFilterMatchingWithAppCompat(
+            IntentArgs args, List<ResolveInfo> resolveInfos) {
+        if (DISABLE_ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS.get()) return;
+
+        // Do not enforce filter matching when the caller is system or root
+        if (ActivityManager.canAccessUnexportedComponents(args.callingUid)) return;
+
+        final Computer computer = (Computer) args.snapshot;
+        final ComponentResolverApi resolver = computer.getComponentResolver();
+
+        final Printer logPrinter = DEBUG_INTENT_MATCHING
+                ? new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM)
+                : null;
+
+        final boolean enforceMatch = Flags.enforceIntentFilterMatch()
+                && args.isChangeEnabled(ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS);
+        final boolean blockNullAction = Flags.blockNullActionIntents()
+                && args.isChangeEnabled(IntentFilter.BLOCK_NULL_ACTION_INTENTS);
+
+        for (int i = resolveInfos.size() - 1; i >= 0; --i) {
+            final ComponentInfo info = resolveInfos.get(i).getComponentInfo();
+
+            // Skip filter matching when the caller is targeting the same app
+            if (UserHandle.isSameApp(args.callingUid, info.applicationInfo.uid)) {
+                continue;
+            }
+
+            final ParsedMainComponent comp = infoToComponent(info, resolver, args.isReceiver);
+
+            if (comp == null || comp.getIntents().isEmpty()) {
+                continue;
+            }
+
+            Boolean match = null;
+
+            if (args.intent.getAction() == null) {
+                args.reportEvent(
+                        UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NULL_ACTION_MATCH,
+                        enforceMatch && blockNullAction);
+                if (blockNullAction) {
+                    // Skip intent filter matching if blocking null action
+                    match = false;
+                }
+            }
+
+            if (match == null) {
+                // Check if any intent filter matches
+                for (int j = 0, size = comp.getIntents().size(); j < size; ++j) {
+                    IntentFilter intentFilter = comp.getIntents().get(j).getIntentFilter();
+                    if (IntentResolver.intentMatchesFilter(
+                            intentFilter, args.intent, args.resolvedType)) {
+                        match = true;
+                        break;
+                    }
+                }
+            }
+
+            // At this point, the value `match` has the following states:
+            // null : Intent does not match any intent filter
+            // false: Null action intent detected AND blockNullAction == true
+            // true : The intent matches at least one intent filter
+
+            if (match == null) {
+                args.reportEvent(
+                        UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH,
+                        enforceMatch);
+                match = false;
+            }
+
+            if (!match) {
+                // All non-matching intents has to be marked accordingly
+                if (Flags.enforceIntentFilterMatch()) {
+                    args.intent.addExtendedFlags(Intent.EXTENDED_FLAG_FILTER_MISMATCH);
+                }
+                if (enforceMatch) {
+                    Slog.w(TAG, "Intent does not match component's intent filter: " + args.intent);
+                    Slog.w(TAG, "Access blocked: " + comp.getComponentName());
+                    if (DEBUG_INTENT_MATCHING) {
+                        Slog.v(TAG, "Component intent filters:");
+                        comp.getIntents().forEach(f -> f.getIntentFilter().dump(logPrinter, "  "));
+                        Slog.v(TAG, "-----------------------------");
+                    }
+                    resolveInfos.remove(i);
+                }
+            }
+        }
+    }
+
+    /**
      * Filter non-exported components from the componentList if intent is implicit.
      * <p>
      * Implicit intents cannot be used to start Services since API 21+.
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 0802e9e..a317e16 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -52,6 +52,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.Flags;
 import android.content.pm.PackageManager;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.SigningDetails;
@@ -63,6 +64,8 @@
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.system.Os;
+import android.system.OsConstants;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -105,6 +108,9 @@
  * Helper class that handles package scanning logic
  */
 final class ScanPackageUtils {
+
+    public static final int PAGE_SIZE_16KB = 16384;
+
     /**
      * Just scans the package without any side effects.
      *
@@ -418,6 +424,37 @@
                     + " abiOverride=" + pkgSetting.getCpuAbiOverride());
         }
 
+        boolean is16KbDevice = Os.sysconf(OsConstants._SC_PAGESIZE) == PAGE_SIZE_16KB;
+        if (Flags.appCompatOption16kb() && is16KbDevice) {
+            // Alignment checks are used decide whether this app should run in compat mode when
+            // nothing was specified in manifest. Manifest should always take precedence over
+            // something decided by platform.
+            if (parsedPackage.getPageSizeAppCompatFlags()
+                    > ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED) {
+                pkgSetting.setPageSizeAppCompatFlags(parsedPackage.getPageSizeAppCompatFlags());
+            } else {
+                // 16 KB is only support for 64 bit ABIs and for apps which are being installed
+                // Check alignment. System, Apex and Platform packages should be page-agnostic now
+                if ((Build.SUPPORTED_64_BIT_ABIS.length > 0)
+                        && !isSystemApp
+                        && !isApex
+                        && !isPlatformPackage) {
+                    int mode =
+                            packageAbiHelper.checkPackageAlignment(
+                                    parsedPackage,
+                                    pkgSetting.getLegacyNativeLibraryPath(),
+                                    parsedPackage.isNativeLibraryRootRequiresIsa(),
+                                    pkgSetting.getCpuAbiOverride());
+                    if (mode >= ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED) {
+                        pkgSetting.setPageSizeAppCompatFlags(mode);
+                    } else {
+                        Slog.e(TAG, "Error occurred while checking alignment of package : "
+                                + parsedPackage.getPackageName());
+                    }
+                }
+            }
+        }
+
         if ((scanFlags & SCAN_BOOTING) == 0 && oldSharedUserSetting != null) {
             // We don't do this here during boot because we can do it all
             // at once after scanning all existing packages.
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 1f672a0..485a280 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3313,6 +3313,11 @@
         if (pkg.getBaseRevisionCode() != 0) {
             serializer.attributeInt(null, "baseRevisionCode", pkg.getBaseRevisionCode());
         }
+        if (pkg.getPageSizeAppCompatFlags()
+                != ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED) {
+            serializer.attributeInt(null, "pageSizeCompat", pkg.getPageSizeAppCompatFlags());
+        }
+
         serializer.attributeFloat(null, "loadingProgress", pkg.getLoadingProgress());
         serializer.attributeLongHex(null, "loadingCompletedTime", pkg.getLoadingCompletedTime());
 
@@ -4129,6 +4134,7 @@
         boolean isScannedAsStoppedSystemApp = false;
         boolean isSdkLibrary = false;
         int baseRevisionCode = 0;
+        int PageSizeCompat = 0;
         try {
             name = parser.getAttributeValue(null, ATTR_NAME);
             realName = parser.getAttributeValue(null, "realName");
@@ -4175,6 +4181,8 @@
             appMetadataSource = parser.getAttributeInt(null, "appMetadataSource",
                     PackageManager.APP_METADATA_SOURCE_UNKNOWN);
             baseRevisionCode = parser.getAttributeInt(null, "baseRevisionCode", 0);
+            PageSizeCompat = parser.getAttributeInt(null, "pageSizeCompat",
+                    ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED);
 
             isScannedAsStoppedSystemApp = parser.getAttributeBoolean(null,
                 "scannedAsStoppedSystemApp", false);
@@ -4330,7 +4338,8 @@
                     .setTargetSdkVersion(targetSdkVersion)
                     .setBaseRevisionCode(baseRevisionCode)
                     .setRestrictUpdateHash(restrictUpdateHash)
-                    .setScannedAsStoppedSystemApp(isScannedAsStoppedSystemApp);
+                    .setScannedAsStoppedSystemApp(isScannedAsStoppedSystemApp)
+                    .setPageSizeAppCompatFlags(PageSizeCompat);
             // Handle legacy string here for single-user mode
             final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
             if (enabledStr != null) {
@@ -5211,6 +5220,10 @@
                 pw.print(" (override=true)");
             }
             pw.println();
+            pw.print(prefix);
+            pw.print("  pageSizeCompat=");
+            pw.print(ps.getPageSizeAppCompatFlags());
+            pw.println();
             if (!ps.getPkg().getQueriesPackages().isEmpty()) {
                 pw.append(prefix).append("  queriesPackages=")
                         .println(ps.getPkg().getQueriesPackages());
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b2b8aaf..066fce0 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -6122,8 +6122,11 @@
             // If the user switch hasn't been explicitly toggled on or off by the user, turn it on.
             if (android.provider.Settings.Global.getString(mContext.getContentResolver(),
                     android.provider.Settings.Global.USER_SWITCHER_ENABLED) == null) {
-                android.provider.Settings.Global.putInt(mContext.getContentResolver(),
-                        android.provider.Settings.Global.USER_SWITCHER_ENABLED, 1);
+                if (Resources.getSystem().getBoolean(
+                        com.android.internal.R.bool.config_enableUserSwitcherUponUserCreation)) {
+                    android.provider.Settings.Global.putInt(mContext.getContentResolver(),
+                            android.provider.Settings.Global.USER_SWITCHER_ENABLED, 1);
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/pkg/PackageState.java b/services/core/java/com/android/server/pm/pkg/PackageState.java
index bbc17c8..33fc066 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageState.java
@@ -22,6 +22,7 @@
 import android.annotation.Size;
 import android.annotation.SystemApi;
 import android.annotation.UserIdInt;
+import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -198,6 +199,21 @@
     int getCategoryOverride();
 
     /**
+     * Returns true if ELF files will be loaded in Page size compatibility mode
+     *
+     * @hide
+     */
+    boolean isPageSizeAppCompatEnabled();
+
+    /**
+     * Returns dialog string based on alignment of uncompressed shared libs inside the APK and ELF
+     * alignment.
+     *
+     * @hide
+     */
+    String getPageSizeCompatWarningMessage(Context context);
+
+    /**
      * The install time CPU override, if any. This value is written at install time
      * and doesn't change during the life of an install. If non-null,
      * {@link #getPrimaryCpuAbiLegacy()} will also contain the same value.
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
index 253eb40..a46c4a6 100644
--- a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
@@ -257,6 +257,16 @@
 
         @NonNull
         @Override
+        public PackageStateWrite setPageSizeAppCompatFlags(
+                @ApplicationInfo.PageSizeAppCompatFlags int mode) {
+            if (mState != null) {
+                mState.setPageSizeAppCompatFlags(mode);
+            }
+            return this;
+        }
+
+        @NonNull
+        @Override
         public PackageStateWrite setUpdateAvailable(boolean updateAvailable) {
             if (mState != null) {
                 mState.setUpdateAvailable(updateAvailable);
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java
index 55d96f3..f8f8695 100644
--- a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java
@@ -46,6 +46,10 @@
     @NonNull
     PackageStateWrite setCategoryOverride(@ApplicationInfo.Category int category);
 
+    /** set 16Kb App compat mode. @see ApplicationInfo.PageSizeAppCompatFlags */
+    @NonNull
+    PackageStateWrite setPageSizeAppCompatFlags(@ApplicationInfo.PageSizeAppCompatFlags int mode);
+
     @NonNull
     PackageStateWrite setUpdateAvailable(boolean updateAvailable);
 
diff --git a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
index 453c6ef..e75f852e 100644
--- a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
+++ b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
@@ -137,6 +137,8 @@
             "com.android.server.policy.PROPERTY_FEATURE_REAR_DISPLAY";
     private static final String PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT =
             "com.android.server.policy.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT";
+    private static final String PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT =
+            "com.android.server.policy.PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT";
 
 
 
@@ -281,6 +283,9 @@
             case PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT:
                 systemProperties.add(DeviceState.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT);
                 break;
+            case PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT:
+                systemProperties.add(DeviceState.PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT);
+                break;
             default:
                 Slog.w(TAG, "Parsed unknown flag with name: " + propertyString);
                 break;
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index 71f67d8..aba15c8 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -34,7 +34,9 @@
 import android.content.pm.PackageManager;
 import android.hardware.power.ChannelConfig;
 import android.hardware.power.CpuHeadroomParams;
+import android.hardware.power.CpuHeadroomResult;
 import android.hardware.power.GpuHeadroomParams;
+import android.hardware.power.GpuHeadroomResult;
 import android.hardware.power.IPower;
 import android.hardware.power.SessionConfig;
 import android.hardware.power.SessionTag;
@@ -79,6 +81,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
@@ -96,10 +99,10 @@
 
     private static final int EVENT_CLEAN_UP_UID = 3;
     @VisibleForTesting  static final int CLEAN_UP_UID_DELAY_MILLIS = 1000;
+    // The minimum interval between the headroom calls as rate limiting.
     private static final int DEFAULT_GPU_HEADROOM_INTERVAL_MILLIS = 1000;
     private static final int DEFAULT_CPU_HEADROOM_INTERVAL_MILLIS = 1000;
     private static final int HEADROOM_INTERVAL_UNSUPPORTED = -1;
-    @VisibleForTesting static final int DEFAULT_HEADROOM_PID = -1;
 
 
     @VisibleForTesting final long mHintSessionPreferredRate;
@@ -184,73 +187,77 @@
     private static final String PROPERTY_SF_ENABLE_CPU_HINT = "debug.sf.enable_adpf_cpu_hint";
     private static final String PROPERTY_HWUI_ENABLE_HINT_MANAGER = "debug.hwui.use_hint_manager";
     private static final String PROPERTY_USE_HAL_HEADROOMS = "persist.hms.use_hal_headrooms";
+    private static final String PROPERTY_CHECK_HEADROOM_TID = "persist.hms.check_headroom_tid";
 
     private Boolean mFMQUsesIntegratedEventFlag = false;
 
     private final Object mCpuHeadroomLock = new Object();
 
-    private static class CpuHeadroomCacheItem {
-        long mExpiredTimeMillis;
-        CpuHeadroomParamsInternal mParams;
-        float[] mHeadroom;
-        long mPid;
 
-        CpuHeadroomCacheItem(long expiredTimeMillis, CpuHeadroomParamsInternal params,
-                float[] headroom, long pid) {
-            mExpiredTimeMillis = expiredTimeMillis;
-            mParams = params;
-            mPid = pid;
-            mHeadroom = headroom;
-        }
+    // this cache tracks the expiration time of the items and performs cleanup on lookup
+    private static class HeadroomCache<K, V> {
+        final List<HeadroomCacheItem> mItemList;
+        final Map<K, HeadroomCacheItem> mKeyItemMap;
+        final long mItemExpDurationMillis;
 
-        private boolean match(CpuHeadroomParamsInternal params, long pid) {
-            if (mParams == null && params == null) return true;
-            if (mParams != null) {
-                return mParams.equals(params) && pid == mPid;
+        class HeadroomCacheItem {
+            long mExpTime;
+            K mKey;
+            V mValue;
+
+            HeadroomCacheItem(K k, V v) {
+                mExpTime = System.currentTimeMillis() + mItemExpDurationMillis;
+                mKey = k;
+                mValue = v;
             }
-            return false;
+
+            boolean isExpired() {
+                return mExpTime <= System.currentTimeMillis();
+            }
         }
 
-        private boolean isExpired() {
-            return System.currentTimeMillis() > mExpiredTimeMillis;
+        void add(K key, V value) {
+            if (mKeyItemMap.containsKey(key)) {
+                final HeadroomCacheItem item = mKeyItemMap.get(key);
+                mItemList.remove(item);
+            }
+            final HeadroomCacheItem item = new HeadroomCacheItem(key, value);
+            mItemList.add(item);
+            mKeyItemMap.put(key, item);
+        }
+
+        V get(K key) {
+            while (!mItemList.isEmpty() && mItemList.getFirst().isExpired()) {
+                mKeyItemMap.remove(mItemList.removeFirst().mKey);
+            }
+            final HeadroomCacheItem item = mKeyItemMap.get(key);
+            if (item == null) {
+                return null;
+            }
+            return item.mValue;
+        }
+
+        HeadroomCache(int size, long expDurationMillis) {
+            mItemList = new LinkedList<>();
+            mKeyItemMap = new ArrayMap<>(size);
+            mItemExpDurationMillis = expDurationMillis;
         }
     }
 
     @GuardedBy("mCpuHeadroomLock")
-    private final List<CpuHeadroomCacheItem> mCpuHeadroomCache;
+    private final HeadroomCache<CpuHeadroomParams, CpuHeadroomResult> mCpuHeadroomCache;
     private final long mCpuHeadroomIntervalMillis;
 
     private final Object mGpuHeadroomLock = new Object();
 
-    private static class GpuHeadroomCacheItem {
-        long mExpiredTimeMillis;
-        GpuHeadroomParamsInternal mParams;
-        float mHeadroom;
-
-        GpuHeadroomCacheItem(long expiredTimeMillis, GpuHeadroomParamsInternal params,
-                float headroom) {
-            mExpiredTimeMillis = expiredTimeMillis;
-            mParams = params;
-            mHeadroom = headroom;
-        }
-
-        private boolean match(GpuHeadroomParamsInternal params) {
-            if (mParams == null && params == null) return true;
-            if (mParams != null) {
-                return mParams.equals(params);
-            }
-            return false;
-        }
-
-        private boolean isExpired() {
-            return System.currentTimeMillis() > mExpiredTimeMillis;
-        }
-    }
-
     @GuardedBy("mGpuHeadroomLock")
-    private final List<GpuHeadroomCacheItem> mGpuHeadroomCache;
+    private final HeadroomCache<GpuHeadroomParams, GpuHeadroomResult> mGpuHeadroomCache;
     private final long mGpuHeadroomIntervalMillis;
 
+    // these are set to default values in CpuHeadroomParamsInternal and GpuHeadroomParamsInternal
+    private final int mDefaultCpuHeadroomCalculationWindowMillis;
+    private final int mDefaultGpuHeadroomCalculationWindowMillis;
+
     @VisibleForTesting
     final IHintManager.Stub mService = new BinderService();
 
@@ -303,26 +310,31 @@
             }
         }
         mCpuHeadroomIntervalMillis = cpuHeadroomIntervalMillis;
+        mDefaultCpuHeadroomCalculationWindowMillis =
+                new CpuHeadroomParamsInternal().calculationWindowMillis;
+        mDefaultGpuHeadroomCalculationWindowMillis =
+                new GpuHeadroomParamsInternal().calculationWindowMillis;
         mGpuHeadroomIntervalMillis = gpuHeadroomIntervalMillis;
         if (mCpuHeadroomIntervalMillis > 0) {
-            mCpuHeadroomCache = new ArrayList<>(4);
+            mCpuHeadroomCache = new HeadroomCache<>(2, mCpuHeadroomIntervalMillis);
         } else {
             mCpuHeadroomCache = null;
         }
         if (mGpuHeadroomIntervalMillis > 0) {
-            mGpuHeadroomCache = new ArrayList<>(2);
+            mGpuHeadroomCache = new HeadroomCache<>(2, mGpuHeadroomIntervalMillis);
         } else {
             mGpuHeadroomCache = null;
         }
     }
 
     private long checkCpuHeadroomSupport() {
+        final CpuHeadroomParams params = new CpuHeadroomParams();
+        params.tids = new int[]{Process.myPid()};
         try {
             synchronized (mCpuHeadroomLock) {
-                final CpuHeadroomParams defaultParams = new CpuHeadroomParams();
-                defaultParams.pid = Process.myPid();
-                float[] ret = mPowerHal.getCpuHeadroom(defaultParams);
-                if (ret != null && ret.length > 0) {
+                final CpuHeadroomResult ret = mPowerHal.getCpuHeadroom(params);
+                if (ret != null && ret.getTag() == CpuHeadroomResult.globalHeadroom
+                        && !Float.isNaN(ret.getGlobalHeadroom())) {
                     return Math.max(
                             DEFAULT_CPU_HEADROOM_INTERVAL_MILLIS,
                             mPowerHal.getCpuHeadroomMinIntervalMillis());
@@ -330,27 +342,29 @@
             }
 
         } catch (UnsupportedOperationException e) {
-            Slog.w(TAG, "getCpuHeadroom HAL API is not supported", e);
+            Slog.w(TAG, "getCpuHeadroom HAL API is not supported, params: " + params, e);
         } catch (RemoteException e) {
-            Slog.e(TAG, "getCpuHeadroom HAL API fails, disabling the API", e);
+            Slog.e(TAG, "getCpuHeadroom HAL API fails, disabling the API, params: " + params, e);
         }
         return HEADROOM_INTERVAL_UNSUPPORTED;
     }
 
     private long checkGpuHeadroomSupport() {
+        final GpuHeadroomParams params = new GpuHeadroomParams();
         try {
             synchronized (mGpuHeadroomLock) {
-                float ret = mPowerHal.getGpuHeadroom(new GpuHeadroomParams());
-                if (!Float.isNaN(ret)) {
+                final GpuHeadroomResult ret = mPowerHal.getGpuHeadroom(params);
+                if (ret != null && ret.getTag() == GpuHeadroomResult.globalHeadroom && !Float.isNaN(
+                        ret.getGlobalHeadroom())) {
                     return Math.max(
                             DEFAULT_GPU_HEADROOM_INTERVAL_MILLIS,
                             mPowerHal.getGpuHeadroomMinIntervalMillis());
                 }
             }
         } catch (UnsupportedOperationException e) {
-            Slog.w(TAG, "getGpuHeadroom HAL API is not supported", e);
+            Slog.w(TAG, "getGpuHeadroom HAL API is not supported, params: " + params, e);
         } catch (RemoteException e) {
-            Slog.e(TAG, "getGpuHeadroom HAL API fails, disabling the API", e);
+            Slog.e(TAG, "getGpuHeadroom HAL API fails, disabling the API, params: " + params, e);
         }
         return HEADROOM_INTERVAL_UNSUPPORTED;
     }
@@ -1445,109 +1459,98 @@
         }
 
         @Override
-        public float[] getCpuHeadroom(@Nullable CpuHeadroomParamsInternal params) {
+        public CpuHeadroomResult getCpuHeadroom(@NonNull CpuHeadroomParamsInternal params) {
             if (mCpuHeadroomIntervalMillis <= 0) {
                 throw new UnsupportedOperationException();
             }
-            CpuHeadroomParams halParams = new CpuHeadroomParams();
-            halParams.pid = Binder.getCallingPid();
-            if (params != null) {
-                halParams.calculationType = params.calculationType;
-                halParams.selectionType = params.selectionType;
-                if (params.usesDeviceHeadroom) {
-                    halParams.pid = DEFAULT_HEADROOM_PID;
+            final CpuHeadroomParams halParams = new CpuHeadroomParams();
+            halParams.tids = new int[]{Binder.getCallingPid()};
+            halParams.calculationType = params.calculationType;
+            halParams.calculationWindowMillis = params.calculationWindowMillis;
+            halParams.selectionType = params.selectionType;
+            if (params.usesDeviceHeadroom) {
+                halParams.tids = new int[]{};
+            } else if (params.tids != null && params.tids.length > 0) {
+                if (params.tids.length > 5) {
+                    throw new IllegalArgumentException(
+                            "More than 5 TIDs is requested: " + params.tids.length);
                 }
+                if (SystemProperties.getBoolean(PROPERTY_CHECK_HEADROOM_TID, true)) {
+                    final int tgid = Process.getThreadGroupLeader(Binder.getCallingPid());
+                    for (int tid : params.tids) {
+                        if (Process.getThreadGroupLeader(tid) != tgid) {
+                            throw new SecurityException("TID " + tid
+                                    + " doesn't belong to the calling process with pid "
+                                    + tgid);
+                        }
+                    }
+                }
+                halParams.tids = params.tids;
             }
-            synchronized (mCpuHeadroomLock) {
-                while (!mCpuHeadroomCache.isEmpty()) {
-                    if (mCpuHeadroomCache.getFirst().isExpired()) {
-                        mCpuHeadroomCache.removeFirst();
-                    } else {
-                        break;
-                    }
-                }
-                for (int i = 0; i < mCpuHeadroomCache.size(); ++i) {
-                    final CpuHeadroomCacheItem item = mCpuHeadroomCache.get(i);
-                    if (item.match(params, halParams.pid)) {
-                        item.mExpiredTimeMillis =
-                                System.currentTimeMillis() + mCpuHeadroomIntervalMillis;
-                        mCpuHeadroomCache.remove(i);
-                        mCpuHeadroomCache.add(item);
-                        return item.mHeadroom;
-                    }
+            if (halParams.calculationWindowMillis
+                    == mDefaultCpuHeadroomCalculationWindowMillis) {
+                synchronized (mCpuHeadroomLock) {
+                    final CpuHeadroomResult res = mCpuHeadroomCache.get(halParams);
+                    if (res != null) return res;
                 }
             }
             // return from HAL directly
             try {
-                float[] headroom = mPowerHal.getCpuHeadroom(halParams);
-                if (headroom == null || headroom.length == 0) {
-                    Slog.wtf(TAG,
-                            "CPU headroom from Power HAL is invalid: " + Arrays.toString(headroom));
-                    return new float[]{Float.NaN};
+                final CpuHeadroomResult result = mPowerHal.getCpuHeadroom(halParams);
+                if (result == null) {
+                    Slog.wtf(TAG, "CPU headroom from Power HAL is invalid");
+                    return null;
                 }
-                synchronized (mCpuHeadroomLock) {
-                    mCpuHeadroomCache.add(new CpuHeadroomCacheItem(
-                            System.currentTimeMillis() + mCpuHeadroomIntervalMillis,
-                            params, headroom, halParams.pid
-                    ));
+                if (halParams.calculationWindowMillis
+                        == mDefaultCpuHeadroomCalculationWindowMillis) {
+                    synchronized (mCpuHeadroomLock) {
+                        mCpuHeadroomCache.add(halParams, result);
+                    }
                 }
-                return headroom;
-
+                return result;
             } catch (RemoteException e) {
-                return new float[]{Float.NaN};
+                Slog.e(TAG, "Failed to get CPU headroom from Power HAL", e);
+                return null;
             }
         }
 
         @Override
-        public float getGpuHeadroom(@Nullable GpuHeadroomParamsInternal params) {
+        public GpuHeadroomResult getGpuHeadroom(@NonNull GpuHeadroomParamsInternal params) {
             if (mGpuHeadroomIntervalMillis <= 0) {
                 throw new UnsupportedOperationException();
             }
-            GpuHeadroomParams halParams = new GpuHeadroomParams();
-            if (params != null) {
-                halParams.calculationType = params.calculationType;
-            }
-            synchronized (mGpuHeadroomLock) {
-                while (!mGpuHeadroomCache.isEmpty()) {
-                    if (mGpuHeadroomCache.getFirst().isExpired()) {
-                        mGpuHeadroomCache.removeFirst();
-                    } else {
-                        break;
-                    }
-                }
-                for (int i = 0; i < mGpuHeadroomCache.size(); ++i) {
-                    final GpuHeadroomCacheItem item = mGpuHeadroomCache.get(i);
-                    if (item.match(params)) {
-                        item.mExpiredTimeMillis =
-                                System.currentTimeMillis() + mGpuHeadroomIntervalMillis;
-                        mGpuHeadroomCache.remove(i);
-                        mGpuHeadroomCache.add(item);
-                        return item.mHeadroom;
-                    }
+            final GpuHeadroomParams halParams = new GpuHeadroomParams();
+            halParams.calculationType = params.calculationType;
+            halParams.calculationWindowMillis = params.calculationWindowMillis;
+            if (halParams.calculationWindowMillis
+                    == mDefaultGpuHeadroomCalculationWindowMillis) {
+                synchronized (mGpuHeadroomLock) {
+                    final GpuHeadroomResult res = mGpuHeadroomCache.get(halParams);
+                    if (res != null) return res;
                 }
             }
             // return from HAL directly
             try {
-                float headroom = mPowerHal.getGpuHeadroom(halParams);
-                if (Float.isNaN(headroom)) {
-                    Slog.wtf(TAG,
-                            "GPU headroom from Power HAL is NaN");
-                    return Float.NaN;
+                final GpuHeadroomResult headroom = mPowerHal.getGpuHeadroom(halParams);
+                if (headroom == null) {
+                    Slog.wtf(TAG, "GPU headroom from Power HAL is invalid");
+                    return null;
                 }
-                synchronized (mGpuHeadroomLock) {
-                    mGpuHeadroomCache.add(new GpuHeadroomCacheItem(
-                            System.currentTimeMillis() + mGpuHeadroomIntervalMillis,
-                            params, headroom
-                    ));
+                if (halParams.calculationWindowMillis
+                        == mDefaultGpuHeadroomCalculationWindowMillis) {
+                    synchronized (mGpuHeadroomLock) {
+                        mGpuHeadroomCache.add(halParams, headroom);
+                    }
                 }
                 return headroom;
             } catch (RemoteException e) {
-                return Float.NaN;
+                Slog.e(TAG, "Failed to get GPU headroom from Power HAL", e);
+                return null;
             }
         }
 
         @Override
-        public long getCpuHeadroomMinIntervalMillis() throws RemoteException {
+        public long getCpuHeadroomMinIntervalMillis() {
             if (mCpuHeadroomIntervalMillis <= 0) {
                 throw new UnsupportedOperationException();
             }
@@ -1555,7 +1558,7 @@
         }
 
         @Override
-        public long getGpuHeadroomMinIntervalMillis() throws RemoteException {
+        public long getGpuHeadroomMinIntervalMillis() {
             if (mGpuHeadroomIntervalMillis <= 0) {
                 throw new UnsupportedOperationException();
             }
@@ -1591,17 +1594,23 @@
                 CpuHeadroomParamsInternal params = new CpuHeadroomParamsInternal();
                 params.selectionType = CpuHeadroomParams.SelectionType.ALL;
                 params.usesDeviceHeadroom = true;
-                pw.println("CPU headroom: " + Arrays.toString(getCpuHeadroom(params)));
+                CpuHeadroomResult ret = getCpuHeadroom(params);
+                pw.println("CPU headroom: " + (ret == null ? "N/A" : ret.getGlobalHeadroom()));
                 params = new CpuHeadroomParamsInternal();
                 params.selectionType = CpuHeadroomParams.SelectionType.PER_CORE;
                 params.usesDeviceHeadroom = true;
-                pw.println("CPU headroom per core: " + Arrays.toString(getCpuHeadroom(params)));
+                ret = getCpuHeadroom(params);
+                pw.println("CPU headroom per core: " + (ret == null ? "N/A"
+                        : Arrays.toString(ret.getPerCoreHeadroom())));
             } catch (Exception e) {
+                Slog.d(TAG, "Failed to dump CPU headroom", e);
                 pw.println("CPU headroom: N/A");
             }
             try {
-                pw.println("GPU headroom: " + getGpuHeadroom(null));
+                GpuHeadroomResult ret = getGpuHeadroom(new GpuHeadroomParamsInternal());
+                pw.println("GPU headroom: " + (ret == null ? "N/A" : ret.getGlobalHeadroom()));
             } catch (Exception e) {
+                Slog.d(TAG, "Failed to dump GPU headroom", e);
                 pw.println("GPU headroom: N/A");
             }
         }
diff --git a/services/core/java/com/android/server/power/hint/adpf_flags.aconfig b/services/core/java/com/android/server/power/hint/adpf_flags.aconfig
index 147d76b..97d3483 100644
--- a/services/core/java/com/android/server/power/hint/adpf_flags.aconfig
+++ b/services/core/java/com/android/server/power/hint/adpf_flags.aconfig
@@ -5,3 +5,11 @@
 package: "android.adpf"
 container: "system"
 
+flag {
+    name: "adpf_viewrootimpl_action_down_boost"
+    is_exported: true
+    namespace: "game"
+    description: "Guards boosting on touch in ViewRootImpl."
+    is_fixed_read_only: true
+    bug: "360345939"
+}
diff --git a/services/core/java/com/android/server/power/hint/flags.aconfig b/services/core/java/com/android/server/power/hint/flags.aconfig
index e56b68c..c231f5a 100644
--- a/services/core/java/com/android/server/power/hint/flags.aconfig
+++ b/services/core/java/com/android/server/power/hint/flags.aconfig
@@ -21,3 +21,10 @@
     description: "Set reset_on_fork flag."
     bug: "370988407"
 }
+
+flag {
+    name: "cpu_headroom_affinity_check"
+    namespace: "game"
+    description: "Check affinity on CPU headroom."
+    bug: "346604998"
+}
diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
index 606bd1d..63e8d99 100644
--- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
+++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
@@ -26,6 +26,7 @@
 import android.os.Handler;
 import android.os.Process;
 import android.util.Log;
+import android.util.LogWriter;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -34,6 +35,7 @@
 import com.android.internal.os.MonotonicClock;
 import com.android.internal.os.PowerProfile;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -44,6 +46,8 @@
  */
 public class BatteryUsageStatsProvider {
     private static final String TAG = "BatteryUsageStatsProv";
+    private static final boolean DEBUG = false;
+
     private final Context mContext;
     private final PowerAttributor mPowerAttributor;
     private final PowerStatsStore mPowerStatsStore;
@@ -262,17 +266,25 @@
 
     private BatteryUsageStats getBatteryUsageStats(BatteryStatsImpl stats,
             BatteryUsageStatsQuery query, long currentTimeMs) {
+        BatteryUsageStats batteryUsageStats;
         if ((query.getFlags()
                 & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_ACCUMULATED) != 0) {
-            return getAccumulatedBatteryUsageStats(stats, query, currentTimeMs);
+            batteryUsageStats = getAccumulatedBatteryUsageStats(stats, query, currentTimeMs);
         } else if (query.getAggregatedToTimestamp() == 0) {
             BatteryUsageStats.Builder builder = computeBatteryUsageStats(stats, query,
                     query.getMonotonicStartTime(),
                     query.getMonotonicEndTime(), currentTimeMs);
-            return builder.build();
+            batteryUsageStats = builder.build();
         } else {
-            return getAggregatedBatteryUsageStats(stats, query);
+            batteryUsageStats = getAggregatedBatteryUsageStats(stats, query);
         }
+        if (DEBUG) {
+            Slog.d(TAG, "query = " + query);
+            PrintWriter pw = new PrintWriter(new LogWriter(Log.DEBUG, TAG));
+            batteryUsageStats.dump(pw, "");
+            pw.flush();
+        }
+        return batteryUsageStats;
     }
 
     private BatteryUsageStats getAccumulatedBatteryUsageStats(BatteryStatsImpl stats,
@@ -319,7 +331,7 @@
 
         if (accumulatedStats.builder == null) {
             accumulatedStats.builder = new BatteryUsageStats.Builder(
-                    stats.getCustomEnergyConsumerNames(), false, true, true, true, 0);
+                    stats.getCustomEnergyConsumerNames(), true, true, true, 0);
             accumulatedStats.startWallClockTime = stats.getStartClockTime();
             accumulatedStats.builder.setStatsStartTimestamp(accumulatedStats.startWallClockTime);
         }
@@ -338,8 +350,6 @@
     private BatteryUsageStats.Builder computeBatteryUsageStats(BatteryStatsImpl stats,
             BatteryUsageStatsQuery query, long monotonicStartTime, long monotonicEndTime,
             long currentTimeMs) {
-        final boolean includePowerModels = (query.getFlags()
-                & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
         final boolean includeProcessStateData = ((query.getFlags()
                 & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA) != 0)
                 && stats.isProcessStateDataAvailable();
@@ -353,8 +363,7 @@
         }
 
         final BatteryUsageStats.Builder batteryUsageStatsBuilder = new BatteryUsageStats.Builder(
-                customEnergyConsumerNames, includePowerModels,
-                includeProcessStateData, query.isScreenStateDataNeeded(),
+                customEnergyConsumerNames, includeProcessStateData, query.isScreenStateDataNeeded(),
                 query.isPowerStateDataNeeded(), minConsumedPowerThreshold);
 
         synchronized (stats) {
@@ -444,8 +453,6 @@
 
     private BatteryUsageStats getAggregatedBatteryUsageStats(BatteryStatsImpl stats,
             BatteryUsageStatsQuery query) {
-        final boolean includePowerModels = (query.getFlags()
-                & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
         final boolean includeProcessStateData = ((query.getFlags()
                 & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA) != 0)
                 && stats.isProcessStateDataAvailable();
@@ -453,7 +460,7 @@
 
         final String[] customEnergyConsumerNames = stats.getCustomEnergyConsumerNames();
         final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
-                customEnergyConsumerNames, includePowerModels, includeProcessStateData,
+                customEnergyConsumerNames, includeProcessStateData,
                 query.isScreenStateDataNeeded(), query.isPowerStateDataNeeded(),
                 minConsumedPowerThreshold);
         if (mPowerStatsStore == null) {
diff --git a/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java b/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java
index b2442c8..ef0e63b 100644
--- a/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java
+++ b/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java
@@ -224,13 +224,12 @@
         BatteryConsumer.Key key = getKeyForPartialTotal(batteryUsageStatsBuilder, deviceScope,
                 powerComponentId, screenState, powerState);
         if (key != null) {
-            deviceScope.addConsumedPower(key, totalPower[0],
-                    BatteryConsumer.POWER_MODEL_UNDEFINED);
+            deviceScope.addConsumedPower(key, totalPower[0]);
             deviceScope.addUsageDurationMillis(key, durationMs[0]);
         }
         key = deviceScope.getKey(powerComponentId, BatteryConsumer.PROCESS_STATE_UNSPECIFIED);
         if (key != null) {
-            deviceScope.addConsumedPower(key, totalPower[0], BatteryConsumer.POWER_MODEL_UNDEFINED);
+            deviceScope.addConsumedPower(key, totalPower[0]);
             deviceScope.addUsageDurationMillis(key, durationMs[0]);
         }
     }
@@ -373,7 +372,7 @@
                 BatteryConsumer.Key key = builder.getKey(powerComponentId, procState,
                         resultScreenState, resultPowerState);
                 if (key != null) {
-                    builder.addConsumedPower(key, power, BatteryConsumer.POWER_MODEL_UNDEFINED);
+                    builder.addConsumedPower(key, power);
                     builder.addUsageDurationMillis(key, duration);
                 }
             }
@@ -384,8 +383,7 @@
                         BatteryConsumer.PROCESS_STATE_UNSPECIFIED);
                 if (key != null) {
                     builder.addConsumedPower(key,
-                            powerByProcState[BatteryConsumer.PROCESS_STATE_UNSPECIFIED],
-                            BatteryConsumer.POWER_MODEL_UNDEFINED);
+                            powerByProcState[BatteryConsumer.PROCESS_STATE_UNSPECIFIED]);
                     builder.addUsageDurationMillis(key,
                             durationByProcState[BatteryConsumer.PROCESS_STATE_UNSPECIFIED]);
                 }
@@ -399,11 +397,9 @@
         BatteryConsumer.Key key = getKeyForPartialTotal(batteryUsageStatsBuilder, allAppsScope,
                 powerComponentId, screenState, powerState);
         if (key != null) {
-            allAppsScope.addConsumedPower(key, powerAllApps,
-                    BatteryConsumer.POWER_MODEL_UNDEFINED);
+            allAppsScope.addConsumedPower(key, powerAllApps);
         }
-        allAppsScope.addConsumedPower(powerComponentId, powerAllApps,
-                BatteryConsumer.POWER_MODEL_UNDEFINED);
+        allAppsScope.addConsumedPower(powerComponentId, powerAllApps);
     }
 
     @Nullable
diff --git a/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java b/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
index e780be4..a153607 100644
--- a/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
+++ b/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
@@ -46,7 +46,9 @@
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.security.advancedprotection.features.AdvancedProtectionHook;
 import com.android.server.security.advancedprotection.features.AdvancedProtectionProvider;
+import com.android.server.security.advancedprotection.features.DisallowCellular2GAdvancedProtectionHook;
 import com.android.server.security.advancedprotection.features.DisallowInstallUnknownSourcesAdvancedProtectionHook;
+import com.android.server.security.advancedprotection.features.MemoryTaggingExtensionHook;
 
 import java.io.FileDescriptor;
 import java.util.ArrayList;
@@ -80,6 +82,12 @@
         if (android.security.Flags.aapmFeatureDisableInstallUnknownSources()) {
             mHooks.add(new DisallowInstallUnknownSourcesAdvancedProtectionHook(mContext, enabled));
         }
+        if (android.security.Flags.aapmFeatureMemoryTaggingExtension()) {
+            mHooks.add(new MemoryTaggingExtensionHook(mContext, enabled));
+        }
+        if (android.security.Flags.aapmFeatureDisableCellular2g()) {
+            mHooks.add(new DisallowCellular2GAdvancedProtectionHook(mContext, enabled));
+        }
     }
 
     // Only for tests
@@ -141,7 +149,7 @@
     }
 
     @Override
-    @EnforcePermission(Manifest.permission.SET_ADVANCED_PROTECTION_MODE)
+    @EnforcePermission(Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE)
     public void setAdvancedProtectionEnabled(boolean enabled) {
         setAdvancedProtectionEnabled_enforcePermission();
         final long identity = Binder.clearCallingIdentity();
@@ -159,7 +167,7 @@
     }
 
     @Override
-    @EnforcePermission(Manifest.permission.SET_ADVANCED_PROTECTION_MODE)
+    @EnforcePermission(Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE)
     public List<AdvancedProtectionFeature> getAdvancedProtectionFeatures() {
         getAdvancedProtectionFeatures_enforcePermission();
         List<AdvancedProtectionFeature> features = new ArrayList<>();
@@ -191,7 +199,7 @@
     }
 
     void sendCallbackAdded(boolean enabled, IAdvancedProtectionCallback callback) {
-        Message.obtain(mHandler, MODE_CHANGED, /*enabled*/ enabled ? 1 : 0, /*unused*/ -1,
+        Message.obtain(mHandler, CALLBACK_ADDED, /*enabled*/ enabled ? 1 : 0, /*unused*/ -1,
                         /*callback*/ callback)
                 .sendToTarget();
     }
diff --git a/services/core/java/com/android/server/security/advancedprotection/features/DisallowCellular2GAdvancedProtectionHook.java b/services/core/java/com/android/server/security/advancedprotection/features/DisallowCellular2GAdvancedProtectionHook.java
new file mode 100644
index 0000000..b9c8d3d
--- /dev/null
+++ b/services/core/java/com/android/server/security/advancedprotection/features/DisallowCellular2GAdvancedProtectionHook.java
@@ -0,0 +1,86 @@
+/*
+ * 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.security.advancedprotection.features;
+
+import static android.security.advancedprotection.AdvancedProtectionManager.ADVANCED_PROTECTION_SYSTEM_ENTITY;
+import static android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_DISALLOW_CELLULAR_2G;
+
+import android.annotation.NonNull;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.UserManager;
+import android.security.advancedprotection.AdvancedProtectionFeature;
+import android.telephony.TelephonyManager;
+import android.util.Slog;
+
+/** @hide */
+public final class DisallowCellular2GAdvancedProtectionHook extends AdvancedProtectionHook {
+    private static final String TAG = "AdvancedProtectionDisallowCellular2G";
+
+    private final AdvancedProtectionFeature mFeature =
+            new AdvancedProtectionFeature(FEATURE_ID_DISALLOW_CELLULAR_2G);
+    private final DevicePolicyManager mDevicePolicyManager;
+    private final TelephonyManager mTelephonyManager;
+
+    public DisallowCellular2GAdvancedProtectionHook(@NonNull Context context, boolean enabled) {
+        super(context, enabled);
+        mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class);
+        mTelephonyManager = context.getSystemService(TelephonyManager.class);
+
+        setPolicy(enabled);
+    }
+
+    @NonNull
+    @Override
+    public AdvancedProtectionFeature getFeature() {
+        return mFeature;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return mTelephonyManager.isDataCapable();
+    }
+
+    private void setPolicy(boolean enabled) {
+        Slog.i(TAG, "setPolicy called with " + enabled);
+
+        if (enabled) {
+            Slog.d(TAG, "Setting DISALLOW_CELLULAR_2G_GLOBALLY restriction");
+            mDevicePolicyManager.addUserRestrictionGlobally(
+                    ADVANCED_PROTECTION_SYSTEM_ENTITY, UserManager.DISALLOW_CELLULAR_2G);
+        } else {
+            Slog.d(TAG, "Clearing DISALLOW_CELLULAR_2G_GLOBALLY restriction");
+            mDevicePolicyManager.clearUserRestrictionGlobally(
+                    ADVANCED_PROTECTION_SYSTEM_ENTITY, UserManager.DISALLOW_CELLULAR_2G);
+        }
+    }
+
+    @Override
+    public void onAdvancedProtectionChanged(boolean enabled) {
+        setPolicy(enabled);
+
+        // Leave 2G disabled even if APM is disabled.
+        if (!enabled) {
+            long oldAllowedTypes =
+                    mTelephonyManager.getAllowedNetworkTypesForReason(
+                            TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G);
+            long newAllowedTypes = oldAllowedTypes & ~TelephonyManager.NETWORK_CLASS_BITMASK_2G;
+            mTelephonyManager.setAllowedNetworkTypesForReason(
+                    TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G, newAllowedTypes);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/security/advancedprotection/features/DisallowInstallUnknownSourcesAdvancedProtectionHook.java b/services/core/java/com/android/server/security/advancedprotection/features/DisallowInstallUnknownSourcesAdvancedProtectionHook.java
index 21752e5..a2933d9 100644
--- a/services/core/java/com/android/server/security/advancedprotection/features/DisallowInstallUnknownSourcesAdvancedProtectionHook.java
+++ b/services/core/java/com/android/server/security/advancedprotection/features/DisallowInstallUnknownSourcesAdvancedProtectionHook.java
@@ -19,13 +19,24 @@
 import static android.security.advancedprotection.AdvancedProtectionManager.ADVANCED_PROTECTION_SYSTEM_ENTITY;
 import static android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES;
 
+import android.Manifest;
 import android.annotation.NonNull;
+import android.app.ActivityManagerInternal;
+import android.app.AppGlobals;
+import android.app.AppOpsManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.os.Process;
+import android.os.RemoteException;
 import android.os.UserManager;
 import android.security.advancedprotection.AdvancedProtectionFeature;
 import android.util.Slog;
 
+import com.android.server.LocalServices;
+
 /** @hide */
 public final class DisallowInstallUnknownSourcesAdvancedProtectionHook
         extends AdvancedProtectionHook {
@@ -33,13 +44,25 @@
 
     private final AdvancedProtectionFeature mFeature = new AdvancedProtectionFeature(
             FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES);
+
+    private final ActivityManagerInternal mActivityManagerInternal;
+    private final AppOpsManager mAppOpsManager;
     private final DevicePolicyManager mDevicePolicyManager;
+    private final IPackageManager mIPackageManager;
+    private final PackageManager mPackageManager;
+    private final UserManager mUserManager;
 
     public DisallowInstallUnknownSourcesAdvancedProtectionHook(@NonNull Context context,
             boolean enabled) {
         super(context, enabled);
+        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+        mAppOpsManager = context.getSystemService(AppOpsManager.class);
         mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class);
-        onAdvancedProtectionChanged(enabled);
+        mIPackageManager = AppGlobals.getPackageManager();
+        mUserManager = context.getSystemService(UserManager.class);
+        mPackageManager = context.getPackageManager();
+
+        setRestriction(enabled);
     }
 
     @NonNull
@@ -53,21 +76,48 @@
         return true;
     }
 
-    @Override
-    public void onAdvancedProtectionChanged(boolean enabled) {
+    private void setRestriction(boolean enabled) {
         if (enabled) {
             Slog.d(TAG, "Setting DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY restriction");
             mDevicePolicyManager.addUserRestrictionGlobally(ADVANCED_PROTECTION_SYSTEM_ENTITY,
                     UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
-            return;
+        } else {
+            Slog.d(TAG, "Clearing DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY restriction");
+            mDevicePolicyManager.clearUserRestrictionGlobally(ADVANCED_PROTECTION_SYSTEM_ENTITY,
+                    UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
         }
-        Slog.d(TAG, "Clearing DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY restriction");
-        mDevicePolicyManager.clearUserRestrictionGlobally(ADVANCED_PROTECTION_SYSTEM_ENTITY,
-                UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
+    }
 
-        // TODO(b/369361373):
-        //  1. After clearing the restriction, set AppOpsManager.OP_REQUEST_INSTALL_PACKAGES to
-        //  disabled.
-        //  2. Update dialog strings.
+    @Override
+    public void onAdvancedProtectionChanged(boolean enabled) {
+        setRestriction(enabled);
+        if (enabled) return;
+
+        // Leave OP_REQUEST_INSTALL_PACKAGES disabled when APM is disabled.
+        Slog.d(TAG, "Setting all OP_REQUEST_INSTALL_PACKAGES to MODE_ERRORED");
+        for (UserInfo userInfo : mUserManager.getAliveUsers()) {
+            try {
+                final String[] packagesWithRequestInstallPermission = mIPackageManager
+                        .getAppOpPermissionPackages(
+                                Manifest.permission.REQUEST_INSTALL_PACKAGES, userInfo.id);
+                for (String packageName : packagesWithRequestInstallPermission) {
+                    try {
+                        int uid = mPackageManager.getPackageUidAsUser(packageName, userInfo.id);
+                        boolean isCallerInstrumented = mActivityManagerInternal
+                                .getInstrumentationSourceUid(uid) != Process.INVALID_UID;
+                        if (!isCallerInstrumented) {
+                            mAppOpsManager.setMode(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES, uid,
+                                    packageName, AppOpsManager.MODE_ERRORED);
+                        }
+                    } catch (PackageManager.NameNotFoundException e) {
+                        Slog.e(TAG, "Couldn't retrieve uid for a package: " + e);
+                    }
+                }
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Couldn't retrieve packages with REQUEST_INSTALL_PACKAGES."
+                        + " getAppOpPermissionPackages() threw the following exception: " + e);
+            }
+        }
+        // TODO(b/369361373): Update dialog strings.
     }
 }
diff --git a/services/core/java/com/android/server/security/advancedprotection/features/MemoryTaggingExtensionHook.java b/services/core/java/com/android/server/security/advancedprotection/features/MemoryTaggingExtensionHook.java
new file mode 100644
index 0000000..d3d3937
--- /dev/null
+++ b/services/core/java/com/android/server/security/advancedprotection/features/MemoryTaggingExtensionHook.java
@@ -0,0 +1,81 @@
+/*
+ * 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.security.advancedprotection.features;
+
+import static android.security.advancedprotection.AdvancedProtectionManager.ADVANCED_PROTECTION_SYSTEM_ENTITY;
+import static android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_ENABLE_MTE;
+
+import android.annotation.NonNull;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.SystemProperties;
+import android.security.advancedprotection.AdvancedProtectionFeature;
+import android.util.Slog;
+
+/** @hide */
+public final class MemoryTaggingExtensionHook
+        extends AdvancedProtectionHook {
+    private static final String TAG = "AdvancedProtectionMTE";
+    private static final String MTE_DPM_SYSTEM_PROPERTY =
+            "ro.arm64.memtag.bootctl_device_policy_manager";
+    private static final String MTE_SETTINGS_SYSTEM_PROPERTY =
+            "ro.arm64.memtag.bootctl_settings_toggle";
+
+    private final AdvancedProtectionFeature mFeature = new AdvancedProtectionFeature(
+            FEATURE_ID_ENABLE_MTE);
+    private final DevicePolicyManager mDevicePolicyManager;
+
+    public MemoryTaggingExtensionHook(@NonNull Context context,
+            boolean enabled) {
+        super(context, enabled);
+        mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class);
+        onAdvancedProtectionChanged(enabled);
+    }
+
+    @NonNull
+    @Override
+    public AdvancedProtectionFeature getFeature() {
+        return mFeature;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return SystemProperties.getBoolean(MTE_DPM_SYSTEM_PROPERTY,
+                SystemProperties.getBoolean(MTE_SETTINGS_SYSTEM_PROPERTY, false));
+    }
+
+    @Override
+    public void onAdvancedProtectionChanged(boolean enabled) {
+        if (!isAvailable()) {
+            Slog.i(TAG, "MTE unavailable on device, skipping.");
+            return;
+        }
+        final int mtePolicy;
+        if (enabled) {
+            mtePolicy = DevicePolicyManager.MTE_ENABLED;
+        } else {
+            mtePolicy = DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY;
+        }
+
+        Slog.d(TAG, "Setting MTE state to " + mtePolicy);
+        try {
+            mDevicePolicyManager.setMtePolicy(ADVANCED_PROTECTION_SYSTEM_ENTITY, mtePolicy);
+        } catch (UnsupportedOperationException e) {
+            Slog.i(TAG, "Setting MTE policy unsupported", e);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java b/services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java
index 06e9dcd..0ea88e8 100644
--- a/services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java
+++ b/services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java
@@ -36,6 +36,9 @@
     private static final int MSG_DISABLE = 2;
 
     private static final int STORED_EVENTS_SIZE_LIMIT = 1024;
+    private static final IntrusionDetectionAdminReceiver ADMIN_RECEIVER =
+            new IntrusionDetectionAdminReceiver();
+
     private final IntrusionDetectionService mIntrusionDetectionService;
     private final ArrayList<DataSource> mDataSources;
 
@@ -60,10 +63,19 @@
      * Initialize DataSources
      * @return Whether the initialization succeeds.
      */
-    // TODO: Add the corresponding data sources
     public boolean initialize() {
         SecurityLogSource securityLogSource = new SecurityLogSource(mContext, this);
         mDataSources.add(securityLogSource);
+
+        NetworkLogSource networkLogSource = new NetworkLogSource(mContext, this);
+        ADMIN_RECEIVER.setNetworkLogEventCallback(networkLogSource);
+        mDataSources.add(networkLogSource);
+
+        for (DataSource ds : mDataSources) {
+            if (!ds.initialize()) {
+                return false;
+            }
+        }
         return true;
     }
 
diff --git a/services/core/java/com/android/server/security/intrusiondetection/DataSource.java b/services/core/java/com/android/server/security/intrusiondetection/DataSource.java
index 0bc4482..61fac46 100644
--- a/services/core/java/com/android/server/security/intrusiondetection/DataSource.java
+++ b/services/core/java/com/android/server/security/intrusiondetection/DataSource.java
@@ -18,6 +18,11 @@
 
 public interface DataSource {
     /**
+     * Initialize the data source.
+     */
+    boolean initialize();
+
+    /**
      * Enable the data collection.
      */
     void enable();
diff --git a/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionAdminReceiver.java b/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionAdminReceiver.java
new file mode 100644
index 0000000..dba7374
--- /dev/null
+++ b/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionAdminReceiver.java
@@ -0,0 +1,42 @@
+/*
+ * 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.security.intrusiondetection;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Slog;
+
+public class IntrusionDetectionAdminReceiver extends DeviceAdminReceiver {
+    private static final String TAG = "IntrusionDetectionAdminReceiver";
+
+    private static NetworkLogSource sNetworkLogSource;
+
+    @Override
+    public void onNetworkLogsAvailable(
+            Context context, Intent intent, long batchToken, int networkLogsCount) {
+        if (sNetworkLogSource != null) {
+            sNetworkLogSource.onNetworkLogsAvailable(batchToken);
+        } else {
+            Slog.w(TAG, "Network log receiver is not initialized");
+        }
+    }
+
+    public void setNetworkLogEventCallback(NetworkLogSource networkLogSource) {
+        sNetworkLogSource = networkLogSource;
+    }
+}
diff --git a/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionEventTransportConnection.java b/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionEventTransportConnection.java
index 82f39b3..b25656e 100644
--- a/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionEventTransportConnection.java
+++ b/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionEventTransportConnection.java
@@ -60,7 +60,7 @@
         if (!bindService()) {
             return false;
         }
-        AndroidFuture<Integer> resultFuture = new AndroidFuture<>();
+        AndroidFuture<Boolean> resultFuture = new AndroidFuture<>();
         try {
             mService.initialize(resultFuture);
         } catch (RemoteException e) {
@@ -68,8 +68,8 @@
             unbindService();
             return false;
         }
-        Integer result = getFutureResult(resultFuture);
-        if (result != null && result == 0) {
+        Boolean result = getFutureResult(resultFuture);
+        if (result != null && result == true) {
             return true;
         } else {
             unbindService();
@@ -83,22 +83,22 @@
      * @return Whether the data is added to the binder service.
      */
     public boolean addData(List<IntrusionDetectionEvent> data) {
-        AndroidFuture<Integer> resultFuture = new AndroidFuture<>();
+        AndroidFuture<Boolean> resultFuture = new AndroidFuture<>();
         try {
             mService.addData(data, resultFuture);
         } catch (RemoteException e) {
             Slog.e(TAG, "Remote Exception", e);
             return false;
         }
-        Integer result = getFutureResult(resultFuture);
-        return result != null && result == 0;
+        Boolean result = getFutureResult(resultFuture);
+        return result != null && result == true;
     }
 
     /**
      * Release the BackupTransport binder service.
      */
     public void release() {
-        AndroidFuture<Integer> resultFuture = new AndroidFuture<>();
+        AndroidFuture<Boolean> resultFuture = new AndroidFuture<>();
         try {
             mService.release(resultFuture);
         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java b/services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java
new file mode 100644
index 0000000..1c93d3f
--- /dev/null
+++ b/services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java
@@ -0,0 +1,134 @@
+/*
+ * 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.security.intrusiondetection;
+
+import android.app.admin.ConnectEvent;
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.DnsEvent;
+import android.app.admin.NetworkEvent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.security.intrusiondetection.IntrusionDetectionEvent;
+import android.util.Slog;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class NetworkLogSource implements DataSource {
+
+    private static final String TAG = "IntrusionDetectionEvent NetworkLogSource";
+
+    private DevicePolicyManager mDpm;
+    private ComponentName mAdmin;
+    private DataAggregator mDataAggregator;
+
+    public NetworkLogSource(Context context, DataAggregator dataAggregator) {
+        mDataAggregator = dataAggregator;
+        mDpm = context.getSystemService(DevicePolicyManager.class);
+        mAdmin = new ComponentName(context, IntrusionDetectionAdminReceiver.class);
+    }
+
+    @Override
+    public boolean initialize() {
+        try {
+            if (!mDpm.isAdminActive(mAdmin)) {
+                Slog.e(TAG, "Admin " + mAdmin.flattenToString() + "is not active admin");
+                return false;
+            }
+        } catch (SecurityException e) {
+            Slog.e(TAG, "Security exception in initialize: ", e);
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public void enable() {
+        enableNetworkLog();
+    }
+
+    @Override
+    public void disable() {
+        disableNetworkLog();
+    }
+
+    private void enableNetworkLog() {
+        if (!isNetworkLogEnabled()) {
+            mDpm.setNetworkLoggingEnabled(mAdmin, true);
+        }
+    }
+
+    private void disableNetworkLog() {
+        if (isNetworkLogEnabled()) {
+            mDpm.setNetworkLoggingEnabled(mAdmin, false);
+        }
+    }
+
+    private boolean isNetworkLogEnabled() {
+        return mDpm.isNetworkLoggingEnabled(mAdmin);
+    }
+
+    /**
+     * Retrieve network logs when onNetworkLogsAvailable callback is received.
+     *
+     * @param batchToken The token representing the current batch of network logs.
+     */
+    public void onNetworkLogsAvailable(long batchToken) {
+        List<NetworkEvent> events;
+        try {
+            events = mDpm.retrieveNetworkLogs(mAdmin, batchToken);
+        } catch (SecurityException e) {
+            Slog.e(
+                    TAG,
+                    "Admin "
+                            + mAdmin.flattenToString()
+                            + "does not have permission to retrieve network logs",
+                    e);
+            return;
+        }
+        if (events == null) {
+            if (!isNetworkLogEnabled()) {
+                Slog.w(TAG, "Network logging is disabled");
+            } else {
+                Slog.e(TAG, "Invalid batch token: " + batchToken);
+            }
+            return;
+        }
+
+        List<IntrusionDetectionEvent> intrusionDetectionEvents =
+                events.stream()
+                        .filter(event -> event != null)
+                        .map(event -> toIntrusionDetectionEvent(event))
+                        .collect(Collectors.toList());
+        mDataAggregator.addBatchData(intrusionDetectionEvents);
+    }
+
+    private IntrusionDetectionEvent toIntrusionDetectionEvent(NetworkEvent event) {
+        if (event instanceof DnsEvent) {
+            DnsEvent dnsEvent = (DnsEvent) event;
+            return new IntrusionDetectionEvent(dnsEvent);
+        } else if (event instanceof ConnectEvent) {
+            ConnectEvent connectEvent = (ConnectEvent) event;
+            return new IntrusionDetectionEvent(connectEvent);
+        }
+        throw new IllegalArgumentException(
+                "Invalid event type with ID: "
+                        + event.getId()
+                        + "from package: "
+                        + event.getPackageName());
+    }
+}
diff --git a/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java b/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java
index 226f9d8..c5f736e 100644
--- a/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java
+++ b/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java
@@ -22,6 +22,7 @@
 import android.app.admin.SecurityLog.SecurityEvent;
 import android.content.Context;
 import android.security.intrusiondetection.IntrusionDetectionEvent;
+import android.util.Slog;
 
 import java.util.List;
 import java.util.concurrent.Executor;
@@ -33,7 +34,7 @@
 
     private static final String TAG = "IntrusionDetection SecurityLogSource";
 
-    private SecurityEventCallback mEventCallback = new SecurityEventCallback();
+    private SecurityEventCallback mEventCallback;
     private DevicePolicyManager mDpm;
     private Executor mExecutor;
     private DataAggregator mDataAggregator;
@@ -42,10 +43,27 @@
         mDataAggregator = dataAggregator;
         mDpm = context.getSystemService(DevicePolicyManager.class);
         mExecutor = Executors.newSingleThreadExecutor();
-        mEventCallback = new SecurityEventCallback();
     }
 
     @Override
+    public boolean initialize() {
+        // Confirm caller is system and the device is managed. Otherwise logs will
+        // be redacted.
+        try {
+            if (!mDpm.isDeviceManaged()) {
+                Slog.e(TAG, "Caller does not have device owner permissions");
+                return false;
+            }
+        } catch (SecurityException e) {
+            Slog.e(TAG, "Security exception in initialize: ", e);
+            return false;
+        }
+        mEventCallback = new SecurityEventCallback();
+        return true;
+    }
+
+
+    @Override
     @RequiresPermission(permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
     public void enable() {
         enableAuditLog();
@@ -72,12 +90,8 @@
         }
     }
 
-    /**
-     * Check if security audit logging is enabled for the caller.
-     *
-     * @return Whether security audit logging is enabled.
-     */
-    public boolean isAuditLogEnabled() {
+    @RequiresPermission(permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
+    private boolean isAuditLogEnabled() {
         return mDpm.isAuditLogEnabled();
     }
 
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 887e186..708bca7 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -2528,22 +2528,24 @@
     }
 
     private void notifyDeviceLockedListenersForUser(int userId, boolean locked) {
-        int numListeners = mDeviceLockedStateListeners.beginBroadcast();
-        try {
-            IntStream.range(0, numListeners).forEach(i -> {
-                try {
-                    Integer uid = (Integer) mDeviceLockedStateListeners.getBroadcastCookie(i);
-                    if (userId == uid.intValue()) {
-                        mDeviceLockedStateListeners.getBroadcastItem(i)
-                                .onDeviceLockedStateChanged(locked);
+        synchronized (mDeviceLockedStateListeners) {
+            int numListeners = mDeviceLockedStateListeners.beginBroadcast();
+            try {
+                IntStream.range(0, numListeners).forEach(i -> {
+                    try {
+                        Integer uid = (Integer) mDeviceLockedStateListeners.getBroadcastCookie(i);
+                        if (userId == uid.intValue()) {
+                            mDeviceLockedStateListeners.getBroadcastItem(i)
+                                    .onDeviceLockedStateChanged(locked);
+                        }
+                    } catch (RemoteException re) {
+                        Log.i(TAG, "Service died", re);
                     }
-                } catch (RemoteException re) {
-                    Log.i(TAG, "Service died", re);
-                }
-            });
+                });
 
-        } finally {
-            mDeviceLockedStateListeners.finishBroadcast();
+            } finally {
+                mDeviceLockedStateListeners.finishBroadcast();
+            }
         }
     }
 }
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
index 38bc026..e191ff2 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
@@ -119,14 +119,14 @@
      * If resource holder retains ownership of the resource in a challenge scenario then value is
      * true.
      */
-    private boolean mResourceHolderRetain;
+    private boolean mResourceOwnershipRetention;
 
     private ClientProfile(Builder builder) {
         this.mId = builder.mId;
         this.mTvInputSessionId = builder.mTvInputSessionId;
         this.mUseCase = builder.mUseCase;
         this.mProcessId = builder.mProcessId;
-        this.mResourceHolderRetain = builder.mResourceHolderRetain;
+        this.mResourceOwnershipRetention = builder.mResourceOwnershipRetention;
     }
 
     public int getId() {
@@ -149,8 +149,8 @@
      * Returns true when the resource holder retains ownership of the resource in a challenge
      * scenario.
      */
-    public boolean shouldResourceHolderRetain() {
-        return mResourceHolderRetain;
+    public boolean resourceOwnershipRetentionEnabled() {
+        return mResourceOwnershipRetention;
     }
 
     /**
@@ -199,12 +199,12 @@
      * scenario, when both resource holder and resource challenger have same processId and same
      * priority.
      *
-     * @param resourceHolderRetain Set to true to allow the resource holder to retain ownership, or
-     *     false (or resourceHolderRetain not set at all) to allow the resource challenger to
-     *     acquire the resource. If not explicitly set, resourceHolderRetain is set to false.
+     * @param enabled Set to {@code true} to allow the resource holder to retain ownership,
+     *     or false to allow the resource challenger to acquire the resource.
+     *     If not explicitly set, enabled is set to {@code false}.
      */
-    public void setResourceHolderRetain(boolean resourceHolderRetain) {
-        mResourceHolderRetain = resourceHolderRetain;
+    public void setResourceOwnershipRetention(boolean enabled) {
+        mResourceOwnershipRetention = enabled;
     }
 
     /**
@@ -389,7 +389,7 @@
         private String mTvInputSessionId;
         private int mUseCase;
         private int mProcessId;
-        private boolean mResourceHolderRetain = false;
+        private boolean mResourceOwnershipRetention = false;
 
         Builder(int id) {
             this.mId = id;
@@ -428,12 +428,12 @@
         /**
          * Builder for {@link ClientProfile}.
          *
-         * @param resourceHolderRetain the determining factor for resource ownership during
-         *     challenger scenario. The default behavior favors the resource challenger and grants
-         *     them ownership of the resource if resourceHolderRetain is not explicitly set to true.
+         * @param enabled the determining factor for resource ownership during challenger scenario.
+         *     The default behavior favors the resource challenger and grants them ownership of
+         *     the resource if resourceOwnershipRetention is not explicitly set to true.
          */
-        public Builder resourceHolderRetain(boolean resourceHolderRetain) {
-            this.mResourceHolderRetain = resourceHolderRetain;
+        public Builder resourceOwnershipRetention(boolean enabled) {
+            this.mResourceOwnershipRetention = enabled;
             return this;
         }
 
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index 5ae8c11..bb192c0 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -231,10 +231,10 @@
         }
 
         @Override
-        public void setResourceHolderRetain(int clientId, boolean resourceHolderRetain) {
-            enforceTrmAccessPermission("setResourceHolderRetain");
+        public void setResourceOwnershipRetention(int clientId, boolean enabled) {
+            enforceTrmAccessPermission("setResourceOwnershipRetention");
             synchronized (mLock) {
-                getClientProfile(clientId).setResourceHolderRetain(resourceHolderRetain);
+                getClientProfile(clientId).setResourceOwnershipRetention(enabled);
             }
         }
 
@@ -1079,7 +1079,8 @@
                             || ((requestClient.getPriority() == currentLowestPriority)
                                     && isRequestFromSameProcess
                                     && !(setResourceHolderRetain()
-                                            && requestClient.shouldResourceHolderRetain())))) {
+                                            && requestClient
+                                                    .resourceOwnershipRetentionEnabled())))) {
                 frontendHandle[0] = inUseLowestPriorityFrontend.getHandle();
                 reclaimOwnerId[0] = inUseLowestPriorityFrontend.getOwnerClientId();
                 return true;
@@ -1265,7 +1266,8 @@
                             || ((requestClient.getPriority() == currentLowestPriority)
                                     && isRequestFromSameProcess
                                     && !(setResourceHolderRetain()
-                                            && requestClient.shouldResourceHolderRetain())))) {
+                                            && requestClient
+                                                    .resourceOwnershipRetentionEnabled())))) {
                 lnbHandle[0] = inUseLowestPriorityLnb.getHandle();
                 reclaimOwnerId[0] = inUseLowestPriorityLnb.getOwnerClientId();
                 return true;
@@ -1352,7 +1354,8 @@
                             || ((requestClient.getPriority() == currentLowestPriority)
                                     && isRequestFromSameProcess
                                     && !(setResourceHolderRetain()
-                                            && requestClient.shouldResourceHolderRetain())))) {
+                                            && requestClient
+                                                    .resourceOwnershipRetentionEnabled())))) {
                 casSessionHandle[0] = cas.getHandle();
                 reclaimOwnerId[0] = lowestPriorityOwnerId;
                 return true;
@@ -1439,7 +1442,8 @@
                             || ((requestClient.getPriority() == currentLowestPriority)
                                     && isRequestFromSameProcess
                                     && !(setResourceHolderRetain()
-                                            && requestClient.shouldResourceHolderRetain())))) {
+                                            && requestClient
+                                                    .resourceOwnershipRetentionEnabled())))) {
                 ciCamHandle[0] = ciCam.getHandle();
                 reclaimOwnerId[0] = lowestPriorityOwnerId;
                 return true;
@@ -1677,7 +1681,8 @@
                             || ((requestClient.getPriority() == currentLowestPriority)
                                     && isRequestFromSameProcess
                                     && !(setResourceHolderRetain()
-                                            && requestClient.shouldResourceHolderRetain())))) {
+                                            && requestClient
+                                                    .resourceOwnershipRetentionEnabled())))) {
                 demuxHandle[0] = inUseLowestPriorityDemux.getHandle();
                 reclaimOwnerId[0] = inUseLowestPriorityDemux.getOwnerClientId();
                 return true;
diff --git a/services/core/java/com/android/server/utils/LazyJniRegistrar.java b/services/core/java/com/android/server/utils/LazyJniRegistrar.java
index ac4a92e..6d29e9e 100644
--- a/services/core/java/com/android/server/utils/LazyJniRegistrar.java
+++ b/services/core/java/com/android/server/utils/LazyJniRegistrar.java
@@ -42,6 +42,9 @@
     /** Registers native methods for ConsumerIrService. */
     public static native void registerConsumerIrService();
 
+    /** Registers native methods for GameManagerService. */
+    public static native void registerGameManagerService();
+
     /** Registers native methods for VrManagerService. */
     public static native void registerVrManagerService();
 }
diff --git a/services/core/java/com/android/server/utils/WatchableImpl.java b/services/core/java/com/android/server/utils/WatchableImpl.java
index 8a04ccf..fec4351 100644
--- a/services/core/java/com/android/server/utils/WatchableImpl.java
+++ b/services/core/java/com/android/server/utils/WatchableImpl.java
@@ -33,6 +33,7 @@
     /**
      * The list of observers.
      */
+    @GuardedBy("mObservers")
     protected final ArrayList<Watcher> mObservers = new ArrayList<>();
 
     /**
@@ -83,7 +84,9 @@
      * @return The number of registered observers.
      */
     public int registeredObserverCount() {
-        return mObservers.size();
+        synchronized (mObservers) {
+            return mObservers.size();
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/vcn/Android.bp b/services/core/java/com/android/server/vcn/Android.bp
deleted file mode 100644
index ab5da3e..0000000
--- a/services/core/java/com/android/server/vcn/Android.bp
+++ /dev/null
@@ -1,13 +0,0 @@
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_base_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["frameworks_base_license"],
-}
-
-filegroup {
-    name: "framework-vcn-util-sources",
-    srcs: ["util/**/*.java"],
-}
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index 3392d03..154897e 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -27,6 +27,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.vcn.VcnManager;
+import android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.ParcelUuid;
@@ -45,7 +46,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.annotations.VisibleForTesting.Visibility;
-import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 1fba297..95acb10 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -38,6 +38,7 @@
 import android.net.vcn.VcnConfig;
 import android.net.vcn.VcnGatewayConnectionConfig;
 import android.net.vcn.VcnManager.VcnErrorCode;
+import android.net.vcn.util.LogUtils;
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.Message;
@@ -54,7 +55,6 @@
 import com.android.internal.annotations.VisibleForTesting.Visibility;
 import com.android.server.VcnManagementService.VcnCallback;
 import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
-import com.android.server.vcn.util.LogUtils;
 
 import java.util.Arrays;
 import java.util.Collections;
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 2325f35..9ccf040 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -30,10 +30,10 @@
 import static android.net.vcn.VcnManager.VCN_ERROR_CODE_CONFIG_ERROR;
 import static android.net.vcn.VcnManager.VCN_ERROR_CODE_INTERNAL_ERROR;
 import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR;
+import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import static com.android.server.VcnManagementService.LOCAL_LOG;
 import static com.android.server.VcnManagementService.VDBG;
-import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -78,6 +78,9 @@
 import android.net.vcn.VcnGatewayConnectionConfig;
 import android.net.vcn.VcnManager;
 import android.net.vcn.VcnTransportInfo;
+import android.net.vcn.util.LogUtils;
+import android.net.vcn.util.MtuUtils;
+import android.net.vcn.util.OneWayBoolean;
 import android.net.wifi.WifiInfo;
 import android.os.Handler;
 import android.os.HandlerExecutor;
@@ -103,9 +106,6 @@
 import com.android.server.vcn.routeselection.UnderlyingNetworkController;
 import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkControllerCallback;
 import com.android.server.vcn.routeselection.UnderlyingNetworkRecord;
-import com.android.server.vcn.util.LogUtils;
-import com.android.server.vcn.util.MtuUtils;
-import com.android.server.vcn.util.OneWayBoolean;
 
 import java.io.IOException;
 import java.net.Inet4Address;
diff --git a/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
index 16ab51e..e6a1ff9 100644
--- a/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
+++ b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
@@ -16,8 +16,9 @@
 
 package com.android.server.vcn.routeselection;
 
+import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
+
 import static com.android.internal.annotations.VisibleForTesting.Visibility;
-import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
diff --git a/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
index 0d4c373..86cee55 100644
--- a/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
+++ b/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
@@ -16,8 +16,9 @@
 
 package com.android.server.vcn.routeselection;
 
+import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
+
 import static com.android.server.VcnManagementService.LOCAL_LOG;
-import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
diff --git a/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
index d32e5cc..79c4116 100644
--- a/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
+++ b/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
@@ -23,9 +23,9 @@
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN;
 import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
+import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import static com.android.server.VcnManagementService.LOCAL_LOG;
-import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
index 3eeeece..f7a564a 100644
--- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
+++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
@@ -19,12 +19,12 @@
 import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY;
 import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN;
 import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
+import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
 
 import static com.android.server.VcnManagementService.LOCAL_LOG;
 import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.getWifiEntryRssiThreshold;
 import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.getWifiExitRssiThreshold;
-import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -39,6 +39,7 @@
 import android.net.vcn.VcnCellUnderlyingNetworkTemplate;
 import android.net.vcn.VcnGatewayConnectionConfig;
 import android.net.vcn.VcnUnderlyingNetworkTemplate;
+import android.net.vcn.util.LogUtils;
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.ParcelUuid;
@@ -54,7 +55,6 @@
 import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
 import com.android.server.vcn.VcnContext;
 import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.NetworkEvaluatorCallback;
-import com.android.server.vcn.util.LogUtils;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java
index 08be11e..30f4ed1 100644
--- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java
+++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java
@@ -16,8 +16,9 @@
 
 package com.android.server.vcn.routeselection;
 
+import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
+
 import static com.android.server.VcnManagementService.LOCAL_LOG;
-import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index 9cb8c1a..797a350 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -617,11 +617,11 @@
 
     private void updateRingerMode() {
         synchronized (mLock) {
-            // If audio manager was not loaded yet then assume most restrictive mode.
-            // This will be loaded again as soon as the audio manager is loaded in onSystemReady.
-            mRingerMode = (mAudioManager == null)
-                    ? AudioManager.RINGER_MODE_SILENT
-                    : mAudioManager.getRingerModeInternal();
+            if (mAudioManager == null) {
+                // Service not ready yet or audio service not available, skip this update request.
+                return;
+            }
+            mRingerMode = mAudioManager.getRingerModeInternal();
         }
     }
 
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index d019516..bbef578 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1513,11 +1513,15 @@
             }
             if (wallpaper.getComponent() != null
                     && isPackageModified(wallpaper.getComponent().getPackageName())) {
+                ServiceInfo serviceInfo = null;
                 try {
-                    mContext.getPackageManager().getServiceInfo(wallpaper.getComponent(),
-                            PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
-                } catch (NameNotFoundException e) {
+                    serviceInfo = mIPackageManager.getServiceInfo(
+                            wallpaper.getComponent(), PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, wallpaper.userId);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to call IPackageManager.getServiceInfo", e);
+                }
+                if (serviceInfo == null) {
                     Slog.e(TAG, "Wallpaper component gone, removing: "
                             + wallpaper.getComponent());
                     clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, false, null);
@@ -3177,7 +3181,7 @@
                     throw new IllegalArgumentException("Invalid crop rect supplied: " + crop);
                 }
                 int orientation = screenOrientations[i];
-                if (orientation == ORIENTATION_UNKNOWN && cropMap.size() > 1) {
+                if (orientation == ORIENTATION_UNKNOWN && crops.size() > 1) {
                     throw new IllegalArgumentException("Invalid crops supplied: the UNKNOWN"
                             + "screen orientation should only be used in a singleton map");
                 }
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 7cbacd6..dd76917 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -22,11 +22,9 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
 import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
 
-import static com.android.internal.util.DumpUtils.dumpSparseArray;
 import static com.android.internal.util.DumpUtils.dumpSparseArrayValues;
 import static com.android.server.accessibility.AccessibilityTraceFileProto.ENTRY;
 import static com.android.server.accessibility.AccessibilityTraceFileProto.MAGIC_NUMBER;
@@ -50,23 +48,15 @@
 import static com.android.server.wm.WindowTracingLegacy.WINSCOPE_EXT;
 
 import android.accessibilityservice.AccessibilityTrace;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Application;
 import android.content.Context;
 import android.content.pm.PackageManagerInternal;
-import android.graphics.BLASTBufferQueue;
-import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Insets;
 import android.graphics.Matrix;
-import android.graphics.Paint;
 import android.graphics.Path;
-import android.graphics.PixelFormat;
 import android.graphics.Point;
-import android.graphics.PorterDuff.Mode;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
@@ -84,25 +74,16 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
-import android.util.TypedValue;
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
 import android.view.MagnificationSpec;
 import android.view.Surface;
-import android.view.Surface.OutOfResourcesException;
-import android.view.SurfaceControl;
 import android.view.ViewConfiguration;
 import android.view.WindowInfo;
 import android.view.WindowManager;
 import android.view.WindowManager.TransitionFlags;
 import android.view.WindowManager.TransitionType;
-import android.view.WindowManagerPolicyConstants;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
 
-import com.android.internal.R;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.TraceBuffer;
 import com.android.internal.util.function.pooled.PooledLambda;
@@ -112,7 +93,6 @@
 import com.android.server.wm.WindowManagerInternal.AccessibilityControllerInternal;
 import com.android.server.wm.WindowManagerInternal.MagnificationCallbacks;
 import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
-import com.android.window.flags.Flags;
 
 import java.io.File;
 import java.io.IOException;
@@ -302,36 +282,6 @@
         }
     }
 
-    /** It is only used by unit test. */
-    @VisibleForTesting
-    Surface forceShowMagnifierSurface(int displayId) {
-        final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
-        if (displayMagnifier != null) {
-            displayMagnifier.mMagnifiedViewport.mWindow.setAlpha(DisplayMagnifier.MagnifiedViewport
-                    .ViewportWindow.AnimationController.MAX_ALPHA);
-            return displayMagnifier.mMagnifiedViewport.mWindow.mSurface;
-        }
-        return null;
-    }
-
-    void onWindowLayersChanged(int displayId) {
-        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
-                | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
-            mAccessibilityTracing.logTrace(TAG + ".onWindowLayersChanged",
-                    FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
-                    "displayId=" + displayId);
-        }
-        final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
-        if (displayMagnifier != null) {
-            displayMagnifier.onWindowLayersChanged();
-        }
-        final WindowsForAccessibilityObserver windowsForA11yObserver =
-                mWindowsForAccessibilityObserver.get(displayId);
-        if (windowsForA11yObserver != null) {
-            windowsForA11yObserver.scheduleComputeChangedWindows();
-        }
-    }
-
     void onDisplaySizeChanged(DisplayContent displayContent) {
 
         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
@@ -564,9 +514,6 @@
     }
 
     void dump(PrintWriter pw, String prefix) {
-        dumpSparseArray(pw, prefix, mDisplayMagnifiers, "magnification display",
-                (index, key) -> pw.printf("%sDisplay #%d:", prefix + "  ", key),
-                dm -> dm.dump(pw, ""));
         dumpSparseArrayValues(pw, prefix, mWindowsForAccessibilityObserver,
                 "windows for accessibility observer");
         mAccessibilityWindowsPopulator.dump(pw, prefix);
@@ -624,7 +571,6 @@
 
         private final Context mDisplayContext;
         private final WindowManagerService mService;
-        private final MagnifiedViewport mMagnifiedViewport;
         private final Handler mHandler;
         private final DisplayContent mDisplayContent;
         private final Display mDisplay;
@@ -661,8 +607,6 @@
             mDisplay = display;
             mHandler = new MyHandler(mService.mH.getLooper());
             mUserContextChangedNotifier = new UserContextChangedNotifier(mHandler);
-            mMagnifiedViewport = Flags.alwaysDrawMagnificationFullscreenBorder()
-                    ? null : new MagnifiedViewport();
             mAccessibilityTracing =
                     AccessibilityController.getAccessibilityControllerInternal(mService);
             mLongAnimationDuration = mDisplayContext.getResources().getInteger(
@@ -704,10 +648,6 @@
             } else {
                 mMagnificationSpec.clear();
             }
-
-            if (!Flags.alwaysDrawMagnificationFullscreenBorder()) {
-                mMagnifiedViewport.setShowMagnifiedBorderIfNeeded();
-            }
         }
 
         void setFullscreenMagnificationActivated(boolean activated) {
@@ -716,10 +656,6 @@
                         FLAGS_MAGNIFICATION_CALLBACK, "activated=" + activated);
             }
             mIsFullscreenMagnificationActivated = activated;
-            if (!Flags.alwaysDrawMagnificationFullscreenBorder()) {
-                mMagnifiedViewport.setMagnifiedRegionBorderShown(activated, true);
-                mMagnifiedViewport.showMagnificationBoundsIfNeeded();
-            }
         }
 
         boolean isFullscreenMagnificationActivated() {
@@ -730,18 +666,6 @@
             return mIsFullscreenMagnificationActivated;
         }
 
-        void onWindowLayersChanged() {
-            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
-                mAccessibilityTracing.logTrace(
-                        LOG_TAG + ".onWindowLayersChanged", FLAGS_MAGNIFICATION_CALLBACK);
-            }
-            if (DEBUG_LAYERS) {
-                Slog.i(LOG_TAG, "Layers changed.");
-            }
-            recomputeBounds();
-            mService.scheduleAnimationLocked();
-        }
-
         void onDisplaySizeChanged(DisplayContent displayContent) {
             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
                 mAccessibilityTracing.logTrace(LOG_TAG + ".onDisplaySizeChanged",
@@ -754,9 +678,6 @@
             }
 
             recomputeBounds();
-            if (!Flags.alwaysDrawMagnificationFullscreenBorder()) {
-                mMagnifiedViewport.onDisplaySizeChanged();
-            }
             mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_DISPLAY_SIZE_CHANGED);
         }
 
@@ -927,10 +848,6 @@
             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
                 mAccessibilityTracing.logTrace(LOG_TAG + ".destroy", FLAGS_MAGNIFICATION_CALLBACK);
             }
-
-            if (!Flags.alwaysDrawMagnificationFullscreenBorder()) {
-                mMagnifiedViewport.destroyWindow();
-            }
         }
 
         void recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded() {
@@ -940,10 +857,6 @@
                         FLAGS_MAGNIFICATION_CALLBACK);
             }
             recomputeBounds();
-
-            if (!Flags.alwaysDrawMagnificationFullscreenBorder()) {
-                mMagnifiedViewport.drawWindowIfNeeded();
-            }
         }
 
         void recomputeBounds() {
@@ -1051,16 +964,9 @@
             }
             visibleWindows.clear();
 
-            if (!Flags.alwaysDrawMagnificationFullscreenBorder()) {
-                mMagnifiedViewport.intersectWithDrawBorderInset(screenWidth, screenHeight);
-            }
-
             final boolean magnifiedChanged =
                     !mOldMagnificationRegion.equals(mMagnificationRegion);
             if (magnifiedChanged) {
-                if (!Flags.alwaysDrawMagnificationFullscreenBorder()) {
-                    mMagnifiedViewport.updateBorderDrawingStatus(screenWidth, screenHeight);
-                }
                 mOldMagnificationRegion.set(mMagnificationRegion);
                 final SomeArgs args = SomeArgs.obtain();
                 args.arg1 = Region.obtain(mMagnificationRegion);
@@ -1140,420 +1046,11 @@
             outSize.set(bounds.width(), bounds.height());
         }
 
-        void dump(PrintWriter pw, String prefix) {
-            if (!Flags.alwaysDrawMagnificationFullscreenBorder()) {
-                mMagnifiedViewport.dump(pw, prefix);
-            }
-        }
-
-        private final class MagnifiedViewport {
-
-            private final float mBorderWidth;
-            private final int mHalfBorderWidth;
-            private final int mDrawBorderInset;
-
-            @Nullable private final ViewportWindow mWindow;
-
-            private boolean mFullRedrawNeeded;
-
-            MagnifiedViewport() {
-                mBorderWidth = mDisplayContext.getResources().getDimension(
-                        com.android.internal.R.dimen.accessibility_magnification_indicator_width);
-                mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2);
-                mDrawBorderInset = (int) mBorderWidth / 2;
-                mWindow = new ViewportWindow(mDisplayContext);
-            }
-
-            void updateBorderDrawingStatus(int screenWidth, int screenHeight) {
-                mWindow.setBounds(mMagnificationRegion);
-                final Rect dirtyRect = mTempRect1;
-                if (mFullRedrawNeeded) {
-                    mFullRedrawNeeded = false;
-                    dirtyRect.set(mDrawBorderInset, mDrawBorderInset,
-                            screenWidth - mDrawBorderInset,
-                            screenHeight - mDrawBorderInset);
-                    mWindow.invalidate(dirtyRect);
-                } else {
-                    final Region dirtyRegion = mTempRegion3;
-                    dirtyRegion.set(mMagnificationRegion);
-                    dirtyRegion.op(mOldMagnificationRegion, Region.Op.XOR);
-                    dirtyRegion.getBounds(dirtyRect);
-                    mWindow.invalidate(dirtyRect);
-                }
-            }
-
-            void setShowMagnifiedBorderIfNeeded() {
-                // If this message is pending, we are in a rotation animation and do not want
-                // to show the border. We will do so when the pending message is handled.
-                if (!mHandler.hasMessages(
-                        MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
-                    setMagnifiedRegionBorderShown(
-                            isFullscreenMagnificationActivated(), true);
-                }
-            }
-
-            // Can be called outside of a surface transaction
-            void showMagnificationBoundsIfNeeded() {
-                if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
-                    mAccessibilityTracing.logTrace(LOG_TAG + ".showMagnificationBoundsIfNeeded",
-                            FLAGS_MAGNIFICATION_CALLBACK);
-                }
-                mHandler.obtainMessage(MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)
-                        .sendToTarget();
-            }
-
-            void intersectWithDrawBorderInset(int screenWidth, int screenHeight) {
-                mMagnificationRegion.op(mDrawBorderInset, mDrawBorderInset,
-                        screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset,
-                        Region.Op.INTERSECT);
-            }
-
-            void onDisplaySizeChanged() {
-                // If fullscreen magnification is activated, hide the border immediately so
-                // the user does not see strange artifacts during display size changed caused by
-                // rotation or folding/unfolding the device. In the rotation case, the
-                // screenshot used for rotation already has the border. After the rotation is
-                // completed we will show the border.
-                if (isFullscreenMagnificationActivated()) {
-                    setMagnifiedRegionBorderShown(false, false);
-                    final long delay = (long) (mLongAnimationDuration
-                            * mService.getWindowAnimationScaleLocked());
-                    Message message = mHandler.obtainMessage(
-                            MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED);
-                    mHandler.sendMessageDelayed(message, delay);
-                }
-                mWindow.updateSize();
-            }
-
-            void setMagnifiedRegionBorderShown(boolean shown, boolean animate) {
-                if (mWindow.setShown(shown, animate)) {
-                    mFullRedrawNeeded = true;
-                    // Clear the old region, so recomputeBounds will refresh the current region.
-                    mOldMagnificationRegion.set(0, 0, 0, 0);
-                }
-            }
-
-            void drawWindowIfNeeded() {
-                mWindow.postDrawIfNeeded();
-            }
-
-            void destroyWindow() {
-                mWindow.releaseSurface();
-            }
-
-            void dump(PrintWriter pw, String prefix) {
-                mWindow.dump(pw, prefix);
-            }
-
-            // TODO(291891390): Remove this class when we clean up the flag
-            //  alwaysDrawMagnificationFullscreenBorder
-            private final class ViewportWindow implements Runnable {
-                private static final String SURFACE_TITLE = "Magnification Overlay";
-
-                private final Region mBounds = new Region();
-                private final Rect mDirtyRect = new Rect();
-                private final Paint mPaint = new Paint();
-
-                private final SurfaceControl mSurfaceControl;
-                /** After initialization, it should only be accessed from animation thread. */
-                private final SurfaceControl.Transaction mTransaction;
-                private final BLASTBufferQueue mBlastBufferQueue;
-                private final Surface mSurface;
-
-                private final AnimationController mAnimationController;
-
-                private boolean mShown;
-                private boolean mLastSurfaceShown;
-                private int mAlpha;
-                private int mPreviousAlpha;
-
-                private volatile boolean mInvalidated;
-
-                ViewportWindow(Context context) {
-                    SurfaceControl surfaceControl = null;
-                    try {
-                        surfaceControl = mDisplayContent
-                                .makeOverlay()
-                                .setName(SURFACE_TITLE)
-                                .setBLASTLayer()
-                                .setFormat(PixelFormat.TRANSLUCENT)
-                                .setCallsite("ViewportWindow")
-                                .build();
-                    } catch (OutOfResourcesException oore) {
-                        /* ignore */
-                    }
-                    mSurfaceControl = surfaceControl;
-                    mDisplay.getRealSize(mScreenSize);
-                    mBlastBufferQueue = new BLASTBufferQueue(SURFACE_TITLE, mSurfaceControl,
-                            mScreenSize.x, mScreenSize.y, PixelFormat.RGBA_8888);
-
-                    final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
-                    final int layer =
-                            mService.mPolicy.getWindowLayerFromTypeLw(TYPE_MAGNIFICATION_OVERLAY) *
-                                    WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER;
-                    t.setLayer(mSurfaceControl, layer).setPosition(mSurfaceControl, 0, 0);
-                    InputMonitor.setTrustedOverlayInputInfo(mSurfaceControl, t,
-                            mDisplayContent.getDisplayId(), "Magnification Overlay");
-                    t.apply();
-                    mTransaction = t;
-                    mSurface = mBlastBufferQueue.createSurface();
-
-                    mAnimationController = new AnimationController(context,
-                            mService.mH.getLooper());
-
-                    TypedValue typedValue = new TypedValue();
-                    context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight,
-                            typedValue, true);
-                    final int borderColor = context.getColor(typedValue.resourceId);
-
-                    mPaint.setStyle(Paint.Style.STROKE);
-                    mPaint.setStrokeWidth(mBorderWidth);
-                    mPaint.setColor(borderColor);
-
-                    mInvalidated = true;
-                }
-
-                /** Returns {@code true} if the state is changed to shown. */
-                boolean setShown(boolean shown, boolean animate) {
-                    synchronized (mService.mGlobalLock) {
-                        if (mShown == shown) {
-                            return false;
-                        }
-                        mShown = shown;
-                        mAnimationController.onFrameShownStateChanged(shown, animate);
-                        if (DEBUG_VIEWPORT_WINDOW) {
-                            Slog.i(LOG_TAG, "ViewportWindow shown: " + mShown);
-                        }
-                    }
-                    return shown;
-                }
-
-                @SuppressWarnings("unused")
-                // Called reflectively from an animator.
-                int getAlpha() {
-                    synchronized (mService.mGlobalLock) {
-                        return mAlpha;
-                    }
-                }
-
-                void setAlpha(int alpha) {
-                    synchronized (mService.mGlobalLock) {
-                        if (mAlpha == alpha) {
-                            return;
-                        }
-                        mAlpha = alpha;
-                        invalidate(null);
-                        if (DEBUG_VIEWPORT_WINDOW) {
-                            Slog.i(LOG_TAG, "ViewportWindow set alpha: " + alpha);
-                        }
-                    }
-                }
-
-                void setBounds(Region bounds) {
-                    synchronized (mService.mGlobalLock) {
-                        if (mBounds.equals(bounds)) {
-                            return;
-                        }
-                        mBounds.set(bounds);
-                        invalidate(mDirtyRect);
-                        if (DEBUG_VIEWPORT_WINDOW) {
-                            Slog.i(LOG_TAG, "ViewportWindow set bounds: " + bounds);
-                        }
-                    }
-                }
-
-                void updateSize() {
-                    synchronized (mService.mGlobalLock) {
-                        getDisplaySizeLocked(mScreenSize);
-                        mBlastBufferQueue.update(mSurfaceControl, mScreenSize.x, mScreenSize.y,
-                                PixelFormat.RGBA_8888);
-                        invalidate(mDirtyRect);
-                    }
-                }
-
-                void invalidate(Rect dirtyRect) {
-                    if (dirtyRect != null) {
-                        mDirtyRect.set(dirtyRect);
-                    } else {
-                        mDirtyRect.setEmpty();
-                    }
-                    mInvalidated = true;
-                    mService.scheduleAnimationLocked();
-                }
-
-                void postDrawIfNeeded() {
-                    if (mInvalidated) {
-                        mService.mAnimationHandler.post(this);
-                    }
-                }
-
-                @Override
-                public void run() {
-                    drawOrRemoveIfNeeded();
-                }
-
-                /**
-                 * This method must only be called by animation handler directly to make sure
-                 * thread safe and there is no lock held outside.
-                 */
-                private void drawOrRemoveIfNeeded() {
-                    // Drawing variables (alpha, dirty rect, and bounds) access is synchronized
-                    // using WindowManagerGlobalLock. Grab copies of these values before
-                    // drawing on the canvas so that drawing can be performed outside of the lock.
-                    int alpha;
-                    boolean redrawBounds;
-                    Rect drawingRect = null;
-                    Region drawingBounds = null;
-                    synchronized (mService.mGlobalLock) {
-                        if (mBlastBufferQueue.mNativeObject == 0) {
-                            // Complete removal since releaseSurface has been called.
-                            if (mSurface.isValid()) {
-                                mTransaction.remove(mSurfaceControl).apply();
-                                mSurface.release();
-                            }
-                            return;
-                        }
-                        if (!mInvalidated) {
-                            return;
-                        }
-                        mInvalidated = false;
-
-                        alpha = mAlpha;
-                        // For b/325863281, we should ensure the drawn border path is cleared when
-                        // alpha = 0. Therefore, we cache the last used alpha when drawing as
-                        // mPreviousAlpha and check it here. If mPreviousAlpha > 0, which means
-                        // the border is showing now, then we should still redraw the clear path
-                        // on the canvas so the border is cleared.
-                        redrawBounds = mAlpha > 0 || mPreviousAlpha > 0;
-                        if (redrawBounds) {
-                            drawingBounds = new Region(mBounds);
-                            // Empty dirty rectangle means unspecified.
-                            if (mDirtyRect.isEmpty()) {
-                                mBounds.getBounds(mDirtyRect);
-                            }
-                            mDirtyRect.inset(-mHalfBorderWidth, -mHalfBorderWidth);
-                            drawingRect = new Rect(mDirtyRect);
-                            if (DEBUG_VIEWPORT_WINDOW) {
-                                Slog.i(LOG_TAG, "ViewportWindow bounds: " + mBounds);
-                                Slog.i(LOG_TAG, "ViewportWindow dirty rect: " + mDirtyRect);
-                            }
-                        }
-                    }
-
-                    final boolean showSurface;
-                    // Draw without holding WindowManagerGlobalLock.
-                    if (redrawBounds) {
-                        Canvas canvas = null;
-                        try {
-                            canvas = mSurface.lockCanvas(drawingRect);
-                        } catch (IllegalArgumentException | OutOfResourcesException e) {
-                            /* ignore */
-                        }
-                        if (canvas == null) {
-                            return;
-                        }
-                        canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
-                        mPaint.setAlpha(alpha);
-                        canvas.drawPath(drawingBounds.getBoundaryPath(), mPaint);
-                        mSurface.unlockCanvasAndPost(canvas);
-                        mPreviousAlpha = alpha;
-                    }
-
-                    showSurface = alpha > 0;
-
-                    if (showSurface && !mLastSurfaceShown) {
-                        mTransaction.show(mSurfaceControl).apply();
-                        mLastSurfaceShown = true;
-                    } else if (!showSurface && mLastSurfaceShown) {
-                        mTransaction.hide(mSurfaceControl).apply();
-                        mLastSurfaceShown = false;
-                    }
-                }
-
-                @GuardedBy("mService.mGlobalLock")
-                void releaseSurface() {
-                    mBlastBufferQueue.destroy();
-                    // Post to perform cleanup on the thread which handles mSurface.
-                    mService.mAnimationHandler.post(this);
-                }
-
-                void dump(PrintWriter pw, String prefix) {
-                    pw.println(prefix
-                            + " mBounds= " + mBounds
-                            + " mDirtyRect= " + mDirtyRect
-                            + " mWidth= " + mScreenSize.x
-                            + " mHeight= " + mScreenSize.y);
-                }
-
-                private final class AnimationController extends Handler {
-                    private static final String PROPERTY_NAME_ALPHA = "alpha";
-
-                    private static final int MIN_ALPHA = 0;
-                    private static final int MAX_ALPHA = 255;
-
-                    private static final int MSG_FRAME_SHOWN_STATE_CHANGED = 1;
-
-                    private final ValueAnimator mShowHideFrameAnimator;
-
-                    AnimationController(Context context, Looper looper) {
-                        super(looper);
-                        mShowHideFrameAnimator = ObjectAnimator.ofInt(ViewportWindow.this,
-                                PROPERTY_NAME_ALPHA, MIN_ALPHA, MAX_ALPHA);
-
-                        Interpolator interpolator = new DecelerateInterpolator(2.5f);
-                        final long longAnimationDuration = context.getResources().getInteger(
-                                com.android.internal.R.integer.config_longAnimTime);
-
-                        mShowHideFrameAnimator.setInterpolator(interpolator);
-                        mShowHideFrameAnimator.setDuration(longAnimationDuration);
-                    }
-
-                    void onFrameShownStateChanged(boolean shown, boolean animate) {
-                        obtainMessage(MSG_FRAME_SHOWN_STATE_CHANGED,
-                                shown ? 1 : 0, animate ? 1 : 0).sendToTarget();
-                    }
-
-                    @Override
-                    public void handleMessage(Message message) {
-                        switch (message.what) {
-                            case MSG_FRAME_SHOWN_STATE_CHANGED: {
-                                final boolean shown = message.arg1 == 1;
-                                final boolean animate = message.arg2 == 1;
-
-                                if (animate) {
-                                    if (mShowHideFrameAnimator.isRunning()) {
-                                        mShowHideFrameAnimator.reverse();
-                                    } else {
-                                        if (shown) {
-                                            mShowHideFrameAnimator.start();
-                                        } else {
-                                            mShowHideFrameAnimator.reverse();
-                                        }
-                                    }
-                                } else {
-                                    mShowHideFrameAnimator.cancel();
-                                    if (shown) {
-                                        setAlpha(MAX_ALPHA);
-                                    } else {
-                                        setAlpha(MIN_ALPHA);
-                                    }
-                                }
-                            } break;
-                        }
-                    }
-                }
-            }
-        }
-
         private class MyHandler extends Handler {
             public static final int MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED = 1;
             public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
             public static final int MESSAGE_NOTIFY_DISPLAY_SIZE_CHANGED = 4;
-
-            // TODO(291891390): Remove this field when we clean up the flag
-            //  alwaysDrawMagnificationFullscreenBorder
-            public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
-            public static final int MESSAGE_NOTIFY_IME_WINDOW_VISIBILITY_CHANGED = 6;
+            public static final int MESSAGE_NOTIFY_IME_WINDOW_VISIBILITY_CHANGED = 5;
 
             MyHandler(Looper looper) {
                 super(looper);
@@ -1577,17 +1074,6 @@
                         mCallbacks.onDisplaySizeChanged();
                     } break;
 
-                    case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
-                        synchronized (mService.mGlobalLock) {
-                            if (isFullscreenMagnificationActivated()) {
-                                if (!Flags.alwaysDrawMagnificationFullscreenBorder()) {
-                                    mMagnifiedViewport.setMagnifiedRegionBorderShown(true, true);
-                                }
-                                mService.scheduleAnimationLocked();
-                            }
-                        }
-                    } break;
-
                     case MESSAGE_NOTIFY_IME_WINDOW_VISIBILITY_CHANGED: {
                         final boolean shown = message.arg1 == 1;
                         mCallbacks.onImeWindowVisibilityChanged(shown);
@@ -1784,22 +1270,13 @@
                 mA11yWindowsPopulator.populateVisibleWindowsOnScreenLocked(
                         mDisplayId, visibleWindows);
 
-                if (!com.android.server.accessibility.Flags.computeWindowChangesOnA11yV2()) {
-                    windows = buildWindowInfoListLocked(visibleWindows, screenSize);
-                }
-
                 // Gets the top focused display Id and window token for supporting multi-display.
                 topFocusedDisplayId = mService.mRoot.getTopFocusedDisplayContent().getDisplayId();
                 topFocusedWindowToken = topFocusedWindowState.mClient.asBinder();
             }
 
-            if (com.android.server.accessibility.Flags.computeWindowChangesOnA11yV2()) {
-                mCallback.onAccessibilityWindowsChanged(forceSend, topFocusedDisplayId,
-                        topFocusedWindowToken, screenSize, visibleWindows);
-            } else {
-                mCallback.onWindowsForAccessibilityChanged(forceSend, topFocusedDisplayId,
-                        topFocusedWindowToken, windows);
-            }
+            mCallback.onAccessibilityWindowsChanged(forceSend, topFocusedDisplayId,
+                    topFocusedWindowToken, screenSize, visibleWindows);
 
             // Recycle the windows as we do not need them.
             for (final AccessibilityWindowsPopulator.AccessibilityWindow window : visibleWindows) {
@@ -1808,166 +1285,6 @@
             mInitialized = true;
         }
 
-        // Here are old code paths, called when computeWindowChangesOnA11yV2 flag is disabled.
-        // LINT.IfChange
-
-        /**
-         * From a list of windows, decides windows to be exposed to accessibility based on touchable
-         * region in the screen.
-         */
-        private List<WindowInfo> buildWindowInfoListLocked(List<AccessibilityWindow> visibleWindows,
-                Point screenSize) {
-            final List<WindowInfo> windows = new ArrayList<>();
-            final Set<IBinder> addedWindows = mTempBinderSet;
-            addedWindows.clear();
-
-            boolean focusedWindowAdded = false;
-
-            final int visibleWindowCount = visibleWindows.size();
-
-            Region unaccountedSpace = mTempRegion;
-            unaccountedSpace.set(0, 0, screenSize.x, screenSize.y);
-
-            // Iterate until we figure out what is touchable for the entire screen.
-            for (int i = 0; i < visibleWindowCount; i++) {
-                final AccessibilityWindow a11yWindow = visibleWindows.get(i);
-                final Region regionInWindow = new Region();
-                a11yWindow.getTouchableRegionInWindow(regionInWindow);
-                if (windowMattersToAccessibility(a11yWindow, regionInWindow, unaccountedSpace)) {
-                    addPopulatedWindowInfo(a11yWindow, regionInWindow, windows, addedWindows);
-                    if (windowMattersToUnaccountedSpaceComputation(a11yWindow)) {
-                        updateUnaccountedSpace(a11yWindow, unaccountedSpace);
-                    }
-                    focusedWindowAdded |= a11yWindow.isFocused();
-                } else if (a11yWindow.isUntouchableNavigationBar()) {
-                    // If this widow is navigation bar without touchable region, accounting the
-                    // region of navigation bar inset because all touch events from this region
-                    // would be received by launcher, i.e. this region is a un-touchable one
-                    // for the application.
-                    unaccountedSpace.op(
-                            getSystemBarInsetsFrame(
-                                    mService.mWindowMap.get(a11yWindow.getWindowInfo().token)),
-                            unaccountedSpace,
-                            Region.Op.REVERSE_DIFFERENCE);
-                }
-
-                if (unaccountedSpace.isEmpty() && focusedWindowAdded) {
-                    break;
-                }
-            }
-
-            // Remove child/parent references to windows that were not added.
-            final int windowCount = windows.size();
-            for (int i = 0; i < windowCount; i++) {
-                WindowInfo window = windows.get(i);
-                if (!addedWindows.contains(window.parentToken)) {
-                    window.parentToken = null;
-                }
-                if (window.childTokens != null) {
-                    final int childTokenCount = window.childTokens.size();
-                    for (int j = childTokenCount - 1; j >= 0; j--) {
-                        if (!addedWindows.contains(window.childTokens.get(j))) {
-                            window.childTokens.remove(j);
-                        }
-                    }
-                    // Leave the child token list if empty.
-                }
-            }
-
-            addedWindows.clear();
-
-            return windows;
-        }
-
-        // Some windows should be excluded from unaccounted space computation, though they still
-        // should be reported
-        private boolean windowMattersToUnaccountedSpaceComputation(AccessibilityWindow a11yWindow) {
-            // Do not account space of trusted non-touchable windows, except the split-screen
-            // divider.
-            // If it's not trusted, touch events are not sent to the windows behind it.
-            if (!a11yWindow.isTouchable()
-                    && (a11yWindow.getType() != TYPE_DOCK_DIVIDER)
-                    && a11yWindow.isTrustedOverlay()) {
-                return false;
-            }
-
-            if (a11yWindow.getType() == WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
-                return false;
-            }
-            return true;
-        }
-
-        private boolean windowMattersToAccessibility(AccessibilityWindow a11yWindow,
-                Region regionInScreen, Region unaccountedSpace) {
-            if (a11yWindow.isFocused()) {
-                return true;
-            }
-
-            // Ignore non-touchable windows, except the split-screen divider, which is
-            // occasionally non-touchable but still useful for identifying split-screen
-            // mode and the PIP menu.
-            if (!a11yWindow.isTouchable()
-                    && (a11yWindow.getType() != TYPE_DOCK_DIVIDER
-                    && !a11yWindow.isPIPMenu())) {
-                return false;
-            }
-
-            // If the window is completely covered by other windows - ignore.
-            if (unaccountedSpace.quickReject(regionInScreen)) {
-                return false;
-            }
-
-            // Add windows of certain types not covered by modal windows.
-            if (isReportedWindowType(a11yWindow.getType())) {
-                return true;
-            }
-
-            return false;
-        }
-
-        private void updateUnaccountedSpace(AccessibilityWindow a11yWindow,
-                Region unaccountedSpace) {
-            if (a11yWindow.getType()
-                    != WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
-                // Account for the space this window takes if the window
-                // is not an accessibility overlay which does not change
-                // the reported windows.
-                final Region touchableRegion = mTempRegion2;
-                a11yWindow.getTouchableRegionInScreen(touchableRegion);
-                unaccountedSpace.op(touchableRegion, unaccountedSpace,
-                        Region.Op.REVERSE_DIFFERENCE);
-            }
-        }
-
-        private static void addPopulatedWindowInfo(AccessibilityWindow a11yWindow,
-                Region regionInScreen, List<WindowInfo> out, Set<IBinder> tokenOut) {
-            final WindowInfo window = a11yWindow.getWindowInfo();
-            if (window.token == null) {
-                // The window was used in calculating visible windows but does not have an
-                // associated IWindow token, so exclude it from the list returned to accessibility.
-                return;
-            }
-            window.regionInScreen.set(regionInScreen);
-            window.layer = tokenOut.size();
-            out.add(window);
-            tokenOut.add(window.token);
-        }
-
-        private static boolean isReportedWindowType(int windowType) {
-            return (windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
-                    && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
-                    && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
-                    && windowType != WindowManager.LayoutParams.TYPE_DRAG
-                    && windowType != WindowManager.LayoutParams.TYPE_INPUT_CONSUMER
-                    && windowType != WindowManager.LayoutParams.TYPE_POINTER
-                    && windowType != TYPE_MAGNIFICATION_OVERLAY
-                    && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
-                    && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY
-                    && windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
-        }
-
-        // LINT.ThenChange(/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java)
-
         private WindowState getTopFocusWindow() {
             return mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus;
         }
diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
index fd2a909..7fc11e6 100644
--- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
+++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
@@ -724,8 +724,7 @@
             }
 
             // Compute system bar insets frame if needed.
-            if (com.android.server.accessibility.Flags.computeWindowChangesOnA11yV2()
-                    && windowState != null && instance.isUntouchableNavigationBar()) {
+            if (windowState != null && instance.isUntouchableNavigationBar()) {
                 final InsetsSourceProvider provider =
                         windowState.getControllableInsetProvider();
                 if (provider != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f70dec1..ef33ffe 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3212,26 +3212,44 @@
      * will be ignored.
      */
     boolean isUniversalResizeable() {
-        if (info.applicationInfo.category == ApplicationInfo.CATEGORY_GAME) {
-            return false;
-        }
-        final boolean compatEnabled = Flags.universalResizableByDefault()
-                && mDisplayContent != null && mDisplayContent.getConfiguration()
-                    .smallestScreenWidthDp >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP
-                && mDisplayContent.getIgnoreOrientationRequest()
-                && info.isChangeEnabled(ActivityInfo.UNIVERSAL_RESIZABLE_BY_DEFAULT);
-        if (!compatEnabled && !mWmService.mConstants.mIgnoreActivityOrientationRequest) {
-            return false;
-        }
-        if (mWmService.mConstants.isPackageOptOutIgnoreActivityOrientationRequest(packageName)) {
+        final boolean isLargeScreen = mDisplayContent != null && mDisplayContent.getConfiguration()
+                .smallestScreenWidthDp >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP
+                && mDisplayContent.getIgnoreOrientationRequest();
+        if (!canBeUniversalResizeable(info.applicationInfo, mWmService, isLargeScreen,
+                true /* forActivity */)) {
             return false;
         }
         if (mAppCompatController.mAllowRestrictedResizability.getAsBoolean()) {
             return false;
         }
         // If the user preference respects aspect ratio, then it becomes non-resizable.
-        return !mAppCompatController.getAppCompatOverrides().getAppCompatAspectRatioOverrides()
-                .shouldApplyUserMinAspectRatioOverride();
+        return mAppCompatController.getAppCompatOverrides().getAppCompatAspectRatioOverrides()
+                .userPreferenceCompatibleWithNonResizability();
+    }
+
+    /**
+     * Returns {@code true} if the fixed orientation, aspect ratio, resizability of the application
+     * can be ignored.
+     */
+    static boolean canBeUniversalResizeable(ApplicationInfo appInfo, WindowManagerService wms,
+            boolean isLargeScreen, boolean forActivity) {
+        if (appInfo.category == ApplicationInfo.CATEGORY_GAME) {
+            return false;
+        }
+        final boolean compatEnabled = isLargeScreen && Flags.universalResizableByDefault()
+                && appInfo.isChangeEnabled(ActivityInfo.UNIVERSAL_RESIZABLE_BY_DEFAULT);
+        if (!compatEnabled && !wms.mConstants.mIgnoreActivityOrientationRequest) {
+            return false;
+        }
+        if (wms.mConstants.isPackageOptOutIgnoreActivityOrientationRequest(appInfo.packageName)) {
+            return false;
+        }
+        if (forActivity) {
+            // The caller will check both application and activity level property.
+            return true;
+        }
+        return !AppCompatController.allowRestrictedResizability(wms.mContext.getPackageManager(),
+                appInfo.packageName);
     }
 
     boolean isResizeable() {
@@ -3667,16 +3685,6 @@
 
             pauseKeyDispatchingLocked();
 
-            // We are finishing the top focused activity and its task has nothing to be focused so
-            // the next focusable task should be focused.
-            if (mayAdjustTop && task.topRunningActivity(true /* focusableOnly */)
-                    == null) {
-                task.adjustFocusToNextFocusableTask("finish-top", false /* allowFocusSelf */,
-                            shouldAdjustGlobalFocus);
-            }
-
-            finishActivityResults(resultCode, resultData, resultGrants);
-
             final boolean endTask = task.getTopNonFinishingActivity() == null
                     && !task.isClearingToReuseTask();
             final WindowContainer<?> trigger = endTask ? task : this;
@@ -3687,6 +3695,16 @@
             if (transition != null) {
                 transition.collectClose(trigger);
             }
+            // We are finishing the top focused activity and its task has nothing to be focused so
+            // the next focusable task should be focused.
+            if (mayAdjustTop && task.topRunningActivity(true /* focusableOnly */)
+                    == null) {
+                task.adjustFocusToNextFocusableTask("finish-top", false /* allowFocusSelf */,
+                            shouldAdjustGlobalFocus);
+            }
+
+            finishActivityResults(resultCode, resultData, resultGrants);
+
             if (isState(RESUMED)) {
                 if (endTask) {
                     mAtmService.getTaskChangeNotificationController().notifyTaskRemovalStarted(
@@ -4575,10 +4593,22 @@
                 // at #postWindowRemoveCleanupLocked
                 return false;
             }
+
+            // Link the fixed rotation transform to this activity since we are transferring the
+            // starting window.
+            if (fromActivity.hasFixedRotationTransform()) {
+                mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(this,
+                        false /* checkOpening */);
+            }
             // Do not transfer if the orientation doesn't match, redraw starting window while it is
             // on top will cause flicker.
-            if (fromActivity.getRequestedConfigurationOrientation()
-                    != getRequestedConfigurationOrientation()) {
+            final int fromOrientation = fromActivity.getConfiguration().orientation;
+            final int requestedOrientation = getRequestedConfigurationOrientation();
+            if (requestedOrientation == ORIENTATION_UNDEFINED) {
+                if (fromOrientation != getConfiguration().orientation) {
+                    return false;
+                }
+            } else if (fromOrientation != requestedOrientation) {
                 return false;
             }
             // In this case, the starting icon has already been displayed, so start
@@ -4592,13 +4622,6 @@
 
             final long origId = Binder.clearCallingIdentity();
             try {
-                // Link the fixed rotation transform to this activity since we are transferring the
-                // starting window.
-                if (fromActivity.hasFixedRotationTransform()) {
-                    mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(this,
-                            false /* checkOpening */);
-                }
-
                 // Transfer the starting window over to the new token.
                 mStartingData = fromActivity.mStartingData;
                 mStartingSurface = fromActivity.mStartingSurface;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 2e2ca14..90d3834 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1838,7 +1838,7 @@
                     remoteTransition, null /* displayChange */);
         } else if (result == START_SUCCESS && mStartActivity.isState(RESUMED)) {
             // Do nothing if the activity is started and is resumed directly.
-        } else if (isStarted) {
+        } else if (isStarted && (mBalCode != BAL_BLOCK || mDoResume)) {
             // Make the collecting transition wait until this request is ready.
             if (transition != null) {
                 transition.setReady(started, false);
diff --git a/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java b/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java
index 90c0866..086b11c 100644
--- a/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java
+++ b/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java
@@ -135,6 +135,12 @@
                 && aspectRatio != USER_MIN_ASPECT_RATIO_FULLSCREEN;
     }
 
+    boolean userPreferenceCompatibleWithNonResizability() {
+        final int aspectRatio = getUserMinAspectRatioOverrideCode();
+        return aspectRatio == USER_MIN_ASPECT_RATIO_UNSET
+                || aspectRatio == USER_MIN_ASPECT_RATIO_FULLSCREEN;
+    }
+
     boolean shouldApplyUserFullscreenOverride() {
         if (isUserFullscreenOverrideEnabled()) {
             final int aspectRatio = getUserMinAspectRatioOverrideCode();
diff --git a/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java b/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java
index 9754595..47d30c9 100644
--- a/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java
+++ b/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java
@@ -164,12 +164,14 @@
      * <p>The treatment is enabled when the following conditions are met:
      * <ul>
      * <li>Feature flag gating the camera compatibility free-form treatment is enabled.
-     * <li>Activity is opted in by the device manufacturer with override.
+     * <li>Activity is opted-in using per-app override, or the treatment is enabled for all apps.
      * </ul>
      */
     boolean shouldApplyFreeformTreatmentForCameraCompat() {
-        return Flags.enableCameraCompatForDesktopWindowing() && isChangeEnabled(mActivityRecord,
-                OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT);
+        return Flags.enableCameraCompatForDesktopWindowing() && (isChangeEnabled(mActivityRecord,
+                OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT)
+                || mActivityRecord.mWmService.mAppCompatConfiguration
+                    .isCameraCompatFreeformWindowingTreatmentEnabled());
     }
 
     boolean isOverrideOrientationOnlyForCameraEnabled() {
diff --git a/services/core/java/com/android/server/wm/AppCompatConfiguration.java b/services/core/java/com/android/server/wm/AppCompatConfiguration.java
index 38c6de1..9a15c4a 100644
--- a/services/core/java/com/android/server/wm/AppCompatConfiguration.java
+++ b/services/core/java/com/android/server/wm/AppCompatConfiguration.java
@@ -304,6 +304,11 @@
     // See RefreshCallbackItem for context.
     private boolean mIsCameraCompatRefreshCycleThroughStopEnabled = true;
 
+    // Whether camera compat freeform treatment should be enabled for all eligible activities.
+    // This has the same effect as enabling the per-app override
+    // ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT for every app.
+    private boolean mIsCameraCompatFreeformWindowingTreatmentEnabled = false;
+
     // Whether should ignore app requested orientation in response to an app
     // calling Activity#setRequestedOrientation. See
     // LetterboxUiController#shouldIgnoreRequestedOrientation for details.
@@ -1351,6 +1356,30 @@
     }
 
     /**
+     * Sets whether the camera compatibility treatment in freeform windowing mode is enabled for
+     * all fixed-orientation apps when using camera.
+     */
+    void setIsCameraCompatFreeformWindowingTreatmentEnabled(boolean enabled) {
+        mIsCameraCompatFreeformWindowingTreatmentEnabled = enabled;
+    }
+
+    /**
+     * Whether the camera compatibility treatment in freeform windowing mode is enabled for all
+     * fixed-orientation apps when using camera.
+     */
+    boolean isCameraCompatFreeformWindowingTreatmentEnabled() {
+        return mIsCameraCompatFreeformWindowingTreatmentEnabled;
+    }
+
+    /**
+     * Resets whether the camera compatibility treatment in freeform windowing mode is enabled for
+     * all fixed-orientation apps when using camera.
+     */
+    void resetIsCameraCompatFreeformWindowingTreatmentEnabled() {
+        mIsCameraCompatFreeformWindowingTreatmentEnabled = false;
+    }
+
+    /**
      * Checks whether rotation compat policy for immersive apps that prevents auto rotation
      * into non-optimal screen orientation while in fullscreen is enabled at build time. This is
      * used when we need to safely initialize a component before the {@link DeviceConfig} flag
diff --git a/services/core/java/com/android/server/wm/AppCompatController.java b/services/core/java/com/android/server/wm/AppCompatController.java
index 145a376..330283f 100644
--- a/services/core/java/com/android/server/wm/AppCompatController.java
+++ b/services/core/java/com/android/server/wm/AppCompatController.java
@@ -76,6 +76,11 @@
         mAppCompatSizeCompatModePolicy = new AppCompatSizeCompatModePolicy(mActivityRecord,
                 mAppCompatOverrides);
         mAllowRestrictedResizability = AppCompatUtils.asLazy(() -> {
+            // Application level.
+            if (allowRestrictedResizability(packageManager, mActivityRecord.packageName)) {
+                return true;
+            }
+            // Activity level.
             try {
                 return packageManager.getPropertyAsUser(
                         PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY,
@@ -88,6 +93,15 @@
         });
     }
 
+    static boolean allowRestrictedResizability(PackageManager pm, String packageName) {
+        try {
+            return pm.getProperty(PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY, packageName)
+                    .getBoolean();
+        } catch (PackageManager.NameNotFoundException e) {
+            return false;
+        }
+    }
+
     @NonNull
     TransparentPolicy getTransparentPolicy() {
         return mTransparentPolicy;
diff --git a/services/core/java/com/android/server/wm/AppWarnings.java b/services/core/java/com/android/server/wm/AppWarnings.java
index fcaab2c..601b17c 100644
--- a/services/core/java/com/android/server/wm/AppWarnings.java
+++ b/services/core/java/com/android/server/wm/AppWarnings.java
@@ -32,6 +32,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.Flags;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.os.Build;
@@ -40,6 +41,8 @@
 import android.os.Message;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.system.Os;
+import android.system.OsConstants;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
@@ -76,6 +79,7 @@
     public static final int FLAG_HIDE_COMPILE_SDK = 0x02;
     public static final int FLAG_HIDE_DEPRECATED_SDK = 0x04;
     public static final int FLAG_HIDE_DEPRECATED_ABI = 0x08;
+    public static final int FLAG_HIDE_PAGE_SIZE_MISMATCH = 0x10;
 
     /**
      * Map of package flags for each user.
@@ -101,6 +105,7 @@
     private SparseArray<UnsupportedCompileSdkDialog> mUnsupportedCompileSdkDialogs;
     private SparseArray<DeprecatedTargetSdkVersionDialog> mDeprecatedTargetSdkVersionDialogs;
     private SparseArray<DeprecatedAbiDialog> mDeprecatedAbiDialogs;
+    private SparseArray<PageSizeMismatchDialog> mPageSizeMismatchDialogs;
 
     /** @see android.app.ActivityManager#alwaysShowUnsupportedCompileSdkWarning */
     private final ArraySet<ComponentName> mAlwaysShowUnsupportedCompileSdkWarningActivities =
@@ -250,6 +255,19 @@
         }
     }
 
+    public void showPageSizeMismatchDialogIfNeeded(ActivityRecord r) {
+        // Don't show dialog if the app compat is enabled using property
+        final boolean appCompatEnabled = SystemProperties.getBoolean(
+                "bionic.linker.16kb.app_compat.enabled", false);
+        if (appCompatEnabled) {
+            return;
+        }
+        boolean is16KbDevice = Os.sysconf(OsConstants._SC_PAGESIZE) == 16384;
+        if (is16KbDevice) {
+            mUiHandler.showPageSizeMismatchDialog(r);
+        }
+    }
+
     /**
      * Called when an activity is being started.
      *
@@ -260,6 +278,9 @@
         showUnsupportedDisplaySizeDialogIfNeeded(r);
         showDeprecatedTargetDialogIfNeeded(r);
         showDeprecatedAbiDialogIfNeeded(r);
+        if (Flags.appCompatOption16kb()) {
+            showPageSizeMismatchDialogIfNeeded(r);
+        }
     }
 
     /**
@@ -457,6 +478,41 @@
         }
     }
 
+    @UiThread
+    private void showPageSizeMismatchDialogUiThread(@NonNull ActivityRecord ar) {
+        String warning =
+                mAtm.mContext
+                        .getPackageManager()
+                        .getPageSizeCompatWarningMessage(ar.info.packageName);
+        if (warning == null) {
+            return;
+        }
+
+        final int userId = getUserIdForActivity(ar);
+        PageSizeMismatchDialog pageSizeMismatchDialog;
+        if (mPageSizeMismatchDialogs != null) {
+            pageSizeMismatchDialog = mPageSizeMismatchDialogs.get(userId);
+            if (pageSizeMismatchDialog != null) {
+                pageSizeMismatchDialog.dismiss();
+                mPageSizeMismatchDialogs.remove(userId);
+            }
+        }
+        if (!hasPackageFlag(userId, ar.packageName, FLAG_HIDE_PAGE_SIZE_MISMATCH)) {
+            pageSizeMismatchDialog =
+                    new PageSizeMismatchDialog(
+                            AppWarnings.this,
+                            getUiContextForActivity(ar),
+                            ar.info.applicationInfo,
+                            userId,
+                            warning);
+            pageSizeMismatchDialog.show();
+            if (mPageSizeMismatchDialogs == null) {
+                mPageSizeMismatchDialogs = new SparseArray<>();
+            }
+            mPageSizeMismatchDialogs.put(userId, pageSizeMismatchDialog);
+        }
+    }
+
     /**
      * Dismisses all warnings for the given package.
      * <p>
@@ -510,6 +566,16 @@
                 mDeprecatedAbiDialogs.remove(userId);
             }
         }
+
+        // Hides the "page size app compat" dialog if necessary.
+        if (mPageSizeMismatchDialogs != null) {
+            PageSizeMismatchDialog pageSizeMismatchDialog = mPageSizeMismatchDialogs.get(userId);
+            if (pageSizeMismatchDialog != null
+                    && (name == null || name.equals(pageSizeMismatchDialog.mPackageName))) {
+                pageSizeMismatchDialog.dismiss();
+                mPageSizeMismatchDialogs.remove(userId);
+            }
+        }
     }
 
     /**
@@ -649,6 +715,7 @@
         private static final int MSG_HIDE_DIALOGS_FOR_PACKAGE = 4;
         private static final int MSG_SHOW_DEPRECATED_TARGET_SDK_DIALOG = 5;
         private static final int MSG_SHOW_DEPRECATED_ABI_DIALOG = 6;
+        private static final int MSG_SHOW_PAGE_SIZE_APP_MISMATCH_DIALOG = 7;
 
         public UiHandler(Looper looper) {
             super(looper, null, true);
@@ -681,6 +748,10 @@
                     final ActivityRecord ar = (ActivityRecord) msg.obj;
                     showDeprecatedAbiDialogUiThread(ar);
                 } break;
+                case MSG_SHOW_PAGE_SIZE_APP_MISMATCH_DIALOG: {
+                    final ActivityRecord ar = (ActivityRecord) msg.obj;
+                    showPageSizeMismatchDialogUiThread(ar);
+                } break;
             }
         }
 
@@ -712,6 +783,11 @@
         public void hideDialogsForPackage(String name, int userId) {
             obtainMessage(MSG_HIDE_DIALOGS_FOR_PACKAGE, userId, 0, name).sendToTarget();
         }
+
+        public void showPageSizeMismatchDialog(ActivityRecord r) {
+            removeMessages(MSG_SHOW_PAGE_SIZE_APP_MISMATCH_DIALOG);
+            obtainMessage(MSG_SHOW_PAGE_SIZE_APP_MISMATCH_DIALOG, r).sendToTarget();
+        }
     }
 
     static class BaseDialog {
diff --git a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
index 506477f..cb95b36 100644
--- a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
+++ b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
@@ -65,6 +65,9 @@
     @NonNull
     private final CameraStateMonitor mCameraStateMonitor;
 
+    // TODO(b/380840084): Consider moving this to the CameraStateMonitor, and keeping track of
+    // all current camera activities, especially when the camera access is switching from one app to
+    // another.
     @Nullable
     private Task mCameraTask;
 
@@ -123,8 +126,7 @@
     }
 
     @Override
-    public void onCameraOpened(@NonNull ActivityRecord cameraActivity,
-            @NonNull String cameraId) {
+    public void onCameraOpened(@NonNull ActivityRecord cameraActivity) {
         // Do not check orientation outside of the config recompute, as the app's orientation intent
         // might be obscured by a fullscreen override. Especially for apps which have a camera
         // functionality which is not the main focus of the app: while most of the app might work
@@ -136,18 +138,15 @@
             return;
         }
 
-        cameraActivity.recomputeConfiguration();
-        cameraActivity.getTask().dispatchTaskInfoChangedIfNeeded(/* force= */ true);
-        cameraActivity.ensureActivityConfiguration(/* ignoreVisibility= */ false);
+        mCameraTask = cameraActivity.getTask();
+        updateAndDispatchCameraConfiguration();
     }
 
     @Override
-    public boolean onCameraClosed(@NonNull String cameraId) {
+    public boolean canCameraBeClosed(@NonNull String cameraId) {
         // Top activity in the same task as the camera activity, or `null` if the task is
         // closed.
-        final ActivityRecord topActivity = mCameraTask != null
-                ? mCameraTask.getTopActivity(/* isFinishing */ false, /* includeOverlays */ false)
-                : null;
+        final ActivityRecord topActivity = getTopActivityFromCameraTask();
         if (topActivity != null) {
             if (isActivityForCameraIdRefreshing(topActivity, cameraId)) {
                 ProtoLog.v(WmProtoLogGroups.WM_DEBUG_STATES,
@@ -157,10 +156,36 @@
                 return false;
             }
         }
-        mCameraTask = null;
         return true;
     }
 
+    @Override
+    public void onCameraClosed() {
+        // Top activity in the same task as the camera activity, or `null` if the task is
+        // closed.
+        final ActivityRecord topActivity = getTopActivityFromCameraTask();
+        // Only clean up if the camera is not running - this close signal could be from switching
+        // cameras (e.g. back to front camera, and vice versa).
+        if (topActivity == null || !mCameraStateMonitor.isCameraRunningForActivity(topActivity)) {
+            updateAndDispatchCameraConfiguration();
+            mCameraTask = null;
+        }
+    }
+
+    private void updateAndDispatchCameraConfiguration() {
+        if (mCameraTask == null) {
+            return;
+        }
+        final ActivityRecord activity = getTopActivityFromCameraTask();
+        if (activity != null) {
+            activity.recomputeConfiguration();
+            mCameraTask.dispatchTaskInfoChangedIfNeeded(/* force= */ true);
+            activity.ensureActivityConfiguration(/* ignoreVisibility= */ true);
+        } else {
+            mCameraTask.dispatchTaskInfoChangedIfNeeded(/* force= */ true);
+        }
+    }
+
     boolean shouldCameraCompatControlOrientation(@NonNull ActivityRecord activity) {
         return isCameraRunningAndWindowingModeEligible(activity);
     }
@@ -262,10 +287,17 @@
                 && !activity.isEmbedded();
     }
 
+    @Nullable
+    private ActivityRecord getTopActivityFromCameraTask() {
+        return mCameraTask != null
+                ? mCameraTask.getTopActivity(/* isFinishing */ false, /* includeOverlays */ false)
+                : null;
+    }
+
     private boolean isActivityForCameraIdRefreshing(@NonNull ActivityRecord topActivity,
             @NonNull String cameraId) {
         if (!isTreatmentEnabledForActivity(topActivity, /* checkOrientation= */ true)
-                || mCameraStateMonitor.isCameraWithIdRunningForActivity(topActivity, cameraId)) {
+                || !mCameraStateMonitor.isCameraWithIdRunningForActivity(topActivity, cameraId)) {
             return false;
         }
         return topActivity.mAppCompatController.getAppCompatCameraOverrides().isRefreshRequested();
diff --git a/services/core/java/com/android/server/wm/CameraStateMonitor.java b/services/core/java/com/android/server/wm/CameraStateMonitor.java
index 3b6e30a..3aa3558 100644
--- a/services/core/java/com/android/server/wm/CameraStateMonitor.java
+++ b/services/core/java/com/android/server/wm/CameraStateMonitor.java
@@ -67,6 +67,10 @@
     // when camera connection is closed and we need to clean up our records.
     private final CameraIdPackageNameBiMapping mCameraIdPackageBiMapping =
             new CameraIdPackageNameBiMapping();
+    // TODO(b/380840084): Consider making this a set of CameraId/PackageName pairs. This is to
+    // keep track of camera-closed signals when apps are switching camera access, so that the policy
+    // can restore app configuration when an app closes camera (e.g. loses camera access due to
+    // another app).
     private final Set<String> mScheduledToBeRemovedCameraIdSet = new ArraySet<>();
 
     // TODO(b/336474959): should/can this go in the compat listeners?
@@ -163,15 +167,14 @@
             if (cameraActivity == null || cameraActivity.getTask() == null) {
                 return;
             }
-            notifyListenersCameraOpened(cameraActivity, cameraId);
+            notifyListenersCameraOpened(cameraActivity);
         }
     }
 
-    private void notifyListenersCameraOpened(@NonNull ActivityRecord cameraActivity,
-            @NonNull String cameraId) {
+    private void notifyListenersCameraOpened(@NonNull ActivityRecord cameraActivity) {
         for (int i = 0; i < mCameraStateListeners.size(); i++) {
             CameraCompatStateListener listener = mCameraStateListeners.get(i);
-            listener.onCameraOpened(cameraActivity, cameraId);
+            listener.onCameraOpened(cameraActivity);
         }
     }
 
@@ -224,11 +227,11 @@
                 // Already reconnected to this camera, no need to clean up.
                 return;
             }
-
-            final boolean closeSuccessfulForAllListeners = notifyListenersCameraClosed(cameraId);
-            if (closeSuccessfulForAllListeners) {
+            final boolean canClose = checkCanCloseForAllListeners(cameraId);
+            if (canClose) {
                 // Finish cleaning up.
                 mCameraIdPackageBiMapping.removeCameraId(cameraId);
+                notifyListenersCameraClosed();
             } else {
                 // Not ready to process closure yet - the camera activity might be refreshing.
                 // Try again later.
@@ -238,15 +241,21 @@
     }
 
     /**
-     * @return {@code false} if any listeners have reported issues processing the close.
+     * @return {@code false} if any listener has reported that they cannot process camera close now.
      */
-    private boolean notifyListenersCameraClosed(@NonNull String cameraId) {
-        boolean closeSuccessfulForAllListeners = true;
+    private boolean checkCanCloseForAllListeners(@NonNull String cameraId) {
         for (int i = 0; i < mCameraStateListeners.size(); i++) {
-            closeSuccessfulForAllListeners &= mCameraStateListeners.get(i).onCameraClosed(cameraId);
+            if (!mCameraStateListeners.get(i).canCameraBeClosed(cameraId)) {
+                return false;
+            }
         }
+        return true;
+    }
 
-        return closeSuccessfulForAllListeners;
+    private void notifyListenersCameraClosed() {
+        for (int i = 0; i < mCameraStateListeners.size(); i++) {
+            mCameraStateListeners.get(i).onCameraClosed();
+        }
     }
 
     // TODO(b/335165310): verify that this works in multi instance and permission dialogs.
@@ -297,14 +306,18 @@
         /**
          * Notifies the compat listener that an activity has opened camera.
          */
-        // TODO(b/336474959): try to decouple `cameraId` from the listeners.
-        void onCameraOpened(@NonNull ActivityRecord cameraActivity, @NonNull String cameraId);
+        void onCameraOpened(@NonNull ActivityRecord cameraActivity);
         /**
-         * Notifies the compat listener that camera is closed.
+         * Checks whether a listener is ready to do a cleanup when camera is closed.
          *
-         * @return true if cleanup has been successful - the notifier might try again if false.
+         * <p>The notifier might try again if false is returned.
          */
         // TODO(b/336474959): try to decouple `cameraId` from the listeners.
-        boolean onCameraClosed(@NonNull String cameraId);
+        boolean canCameraBeClosed(@NonNull String cameraId);
+
+        /**
+         * Notifies the compat listener that camera is closed.
+         */
+        void onCameraClosed();
     }
 }
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 0b5872b..93ccd74 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -32,6 +32,7 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.media.projection.IMediaProjectionManager;
+import android.media.projection.StopReason;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -226,6 +227,7 @@
                                 + "size %s",
                         mDisplayContent.getDisplayId(), recordedContentBounds,
                         recordedContentOrientation, surfaceSize);
+
                 updateMirroredSurface(mRecordedWindowContainer.getSyncTransaction(),
                         recordedContentBounds, surfaceSize);
             } else {
@@ -295,12 +297,12 @@
      * Ensure recording does not fall back to the display stack; ensure the recording is stopped
      * and the client notified by tearing down the virtual display.
      */
-    private void stopMediaProjection() {
+    private void stopMediaProjection(@StopReason int stopReason) {
         ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                 "Content Recording: Stop MediaProjection on virtual display %d",
                 mDisplayContent.getDisplayId());
         if (mMediaProjectionManager != null) {
-            mMediaProjectionManager.stopActiveProjection();
+            mMediaProjectionManager.stopActiveProjection(stopReason);
         }
     }
 
@@ -507,7 +509,7 @@
         if (shouldExitTaskRecording) {
             // Clean up the cached session first to ensure recording doesn't re-start, since
             // tearing down the display will generate display events which will trickle back here.
-            stopMediaProjection();
+            stopMediaProjection(StopReason.STOP_ERROR);
         }
     }
 
@@ -599,9 +601,13 @@
         mLastRecordedBounds = new Rect(recordedContentBounds);
         mLastConsumingSurfaceSize.x = surfaceSize.x;
         mLastConsumingSurfaceSize.y = surfaceSize.y;
-        // Request to notify the client about the resize.
-        mMediaProjectionManager.notifyActiveProjectionCapturedContentResized(
-                mLastRecordedBounds.width(), mLastRecordedBounds.height());
+
+        // Request to notify the client about the updated bounds.
+        mMediaProjectionManager.notifyCaptureBoundsChanged(
+                mContentRecordingSession.getContentToRecord(),
+                mContentRecordingSession.getTargetUid(),
+                mLastRecordedBounds
+        );
     }
 
     /**
@@ -641,7 +647,7 @@
         clearContentRecordingSession();
         // Clean up the cached session first to ensure recording doesn't re-start, since
         // tearing down the display will generate display events which will trickle back here.
-        stopMediaProjection();
+        stopMediaProjection(StopReason.STOP_TARGET_REMOVED);
     }
 
     // WindowContainerListener
@@ -674,10 +680,10 @@
     }
 
     @VisibleForTesting interface MediaProjectionManagerWrapper {
-        void stopActiveProjection();
-        void notifyActiveProjectionCapturedContentResized(int width, int height);
+        void stopActiveProjection(@StopReason int stopReason);
         void notifyActiveProjectionCapturedContentVisibilityChanged(boolean isVisible);
         void notifyWindowingModeChanged(int contentToRecord, int targetUid, int windowingMode);
+        void notifyCaptureBoundsChanged(int contentToRecord, int targetUid, Rect captureBounds);
     }
 
     private static final class RemoteMediaProjectionManagerWrapper implements
@@ -691,7 +697,7 @@
         }
 
         @Override
-        public void stopActiveProjection() {
+        public void stopActiveProjection(@StopReason int stopReason) {
             fetchMediaProjectionManager();
             if (mIMediaProjectionManager == null) {
                 return;
@@ -700,7 +706,7 @@
                 ProtoLog.e(WM_DEBUG_CONTENT_RECORDING,
                         "Content Recording: stopping active projection for display %d",
                         mDisplayId);
-                mIMediaProjectionManager.stopActiveProjection();
+                mIMediaProjectionManager.stopActiveProjection(stopReason);
             } catch (RemoteException e) {
                 ProtoLog.e(WM_DEBUG_CONTENT_RECORDING,
                         "Content Recording: Unable to tell MediaProjectionManagerService to stop "
@@ -710,23 +716,6 @@
         }
 
         @Override
-        public void notifyActiveProjectionCapturedContentResized(int width, int height) {
-            fetchMediaProjectionManager();
-            if (mIMediaProjectionManager == null) {
-                return;
-            }
-            try {
-                mIMediaProjectionManager.notifyActiveProjectionCapturedContentResized(width,
-                        height);
-            } catch (RemoteException e) {
-                ProtoLog.e(WM_DEBUG_CONTENT_RECORDING,
-                        "Content Recording: Unable to tell MediaProjectionManagerService about "
-                                + "resizing the active projection: %s",
-                        e);
-            }
-        }
-
-        @Override
         public void notifyActiveProjectionCapturedContentVisibilityChanged(boolean isVisible) {
             fetchMediaProjectionManager();
             if (mIMediaProjectionManager == null) {
@@ -759,6 +748,22 @@
             }
         }
 
+        @Override
+        public void notifyCaptureBoundsChanged(int contentToRecord, int targetUid,
+                Rect captureBounds) {
+            fetchMediaProjectionManager();
+            if (mIMediaProjectionManager == null) {
+                return;
+            }
+            try {
+                mIMediaProjectionManager.notifyCaptureBoundsChanged(
+                        contentToRecord, targetUid, captureBounds);
+            } catch (RemoteException e) {
+                ProtoLog.e(WM_DEBUG_CONTENT_RECORDING,
+                        "Content Recording: Unable to tell log bounds change: %s", e);
+            }
+        }
+
         private void fetchMediaProjectionManager() {
             if (mIMediaProjectionManager != null) {
                 return;
diff --git a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
index 6f8c17a..4e79e37 100644
--- a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
+++ b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
@@ -403,6 +403,7 @@
                 || first.renderFrameRate != second.renderFrameRate
                 || first.hasArrSupport != second.hasArrSupport
                 || !Objects.equals(first.frameRateCategoryRate, second.frameRateCategoryRate)
+                || !Arrays.equals(first.supportedRefreshRates, second.supportedRefreshRates)
                 || first.defaultModeId != second.defaultModeId
                 || first.userPreferredModeId != second.userPreferredModeId
                 || !Arrays.equals(first.supportedModes, second.supportedModes)
diff --git a/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java b/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java
index c8cb621..43855aa 100644
--- a/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java
+++ b/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java
@@ -196,10 +196,11 @@
 
         if (!aspectRatioOverrides.shouldOverrideMinAspectRatio()
                 && !AppCompatCameraPolicy.shouldOverrideMinAspectRatioForCamera(mActivityRecord)) {
-            if (mActivityRecord.isUniversalResizeable()) {
+            final float minAspectRatio = info.getMinAspectRatio();
+            if (minAspectRatio == 0 || mActivityRecord.isUniversalResizeable()) {
                 return 0;
             }
-            return info.getMinAspectRatio();
+            return minAspectRatio;
         }
 
         if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
@@ -242,10 +243,11 @@
         if (mTransparentPolicy.isRunning()) {
             return mTransparentPolicy.getInheritedMaxAspectRatio();
         }
-        if (mActivityRecord.isUniversalResizeable()) {
+        final float maxAspectRatio = mActivityRecord.info.getMaxAspectRatio();
+        if (maxAspectRatio == 0 || mActivityRecord.isUniversalResizeable()) {
             return 0;
         }
-        return mActivityRecord.info.getMaxAspectRatio();
+        return maxAspectRatio;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e9e550e..fc08a91 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -5502,14 +5502,18 @@
             // Attach the SystemUiContext to this DisplayContent the get latest configuration.
             // Note that the SystemUiContext will be removed automatically if this DisplayContent
             // is detached.
-            final WindowProcessController wpc = mAtmService.getProcessController(
-                    getDisplayUiContext().getIApplicationThread());
-            mWmService.mWindowContextListenerController.registerWindowContainerListener(
-                    wpc, getDisplayUiContext().getWindowContextToken(), this,
-                    INVALID_WINDOW_TYPE, null /* options */);
+            registerSystemUiContext();
         }
     }
 
+    private void registerSystemUiContext() {
+        final WindowProcessController wpc = mAtmService.getProcessController(
+                getDisplayUiContext().getIApplicationThread());
+        mWmService.mWindowContextListenerController.registerWindowContainerListener(
+                wpc, getDisplayUiContext().getWindowContextToken(), this,
+                INVALID_WINDOW_TYPE, null /* options */);
+    }
+
     @Override
     void assignChildLayers(SurfaceControl.Transaction t) {
         assignRelativeLayerForIme(t, false /* forceUpdate */);
@@ -7057,12 +7061,15 @@
         }
 
         @Override
-        public void setImeInputTargetRequestedVisibility(boolean visible) {
+        public void setImeInputTargetRequestedVisibility(boolean visible,
+                @NonNull ImeTracker.Token statsToken) {
             if (android.view.inputmethod.Flags.refactorInsetsController()) {
                 // TODO(b/353463205) we won't have the statsToken in all cases, but should still log
                 try {
-                    mRemoteInsetsController.setImeInputTargetRequestedVisibility(visible);
+                    mRemoteInsetsController.setImeInputTargetRequestedVisibility(visible,
+                            statsToken);
                 } catch (RemoteException e) {
+                    // TODO(b/353463205) fail statsToken
                     Slog.w(TAG, "Failed to deliver setImeInputTargetRequestedVisibility", e);
                 }
             }
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 4cf1fb4..df209ff 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -485,6 +485,9 @@
             if (isDefaultDisplay) {
                 updateOrientationListenerLw();
             }
+        } else if (mCompatPolicyForImmersiveApps != null
+                && mCompatPolicyForImmersiveApps.deferOrientationUpdate()) {
+            return false;
         }
         return updateRotationUnchecked(forceUpdate);
     }
diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
index 0ccc0fe..3c199db 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
@@ -71,6 +71,9 @@
     @NonNull
     private final ActivityRefresher mActivityRefresher;
 
+    // TODO(b/380840084): Consider moving this to the CameraStateMonitor, and keeping track of
+    // all current camera activities, especially when the camera access is switching from one app to
+    // another.
     @Nullable
     private Task mCameraTask;
 
@@ -327,8 +330,7 @@
     }
 
     @Override
-    public void onCameraOpened(@NonNull ActivityRecord cameraActivity,
-            @NonNull String cameraId) {
+    public void onCameraOpened(@NonNull ActivityRecord cameraActivity) {
         mCameraTask = cameraActivity.getTask();
         // Checking whether an activity in fullscreen rather than the task as this camera
         // compat treatment doesn't cover activity embedding.
@@ -374,16 +376,9 @@
     }
 
     @Override
-    public boolean onCameraClosed(@NonNull String cameraId) {
-        final ActivityRecord topActivity;
-        if (Flags.cameraCompatFullscreenPickSameTaskActivity()) {
-            topActivity = mCameraTask != null ? mCameraTask.getTopActivity(
-                    /* includeFinishing= */ true, /* includeOverlays= */ false) : null;
-        } else {
-            topActivity = mDisplayContent.topRunningActivity(/* considerKeyguardState= */ true);
-        }
+    public boolean canCameraBeClosed(@NonNull String cameraId) {
+        final ActivityRecord topActivity = getTopActivity();
 
-        mCameraTask = null;
         if (topActivity == null) {
             return true;
         }
@@ -399,6 +394,23 @@
                 return false;
             }
         }
+        return true;
+    }
+
+    @Override
+    public void onCameraClosed() {
+        final ActivityRecord topActivity = getTopActivity();
+
+        // Only clean up if the camera is not running - this close signal could be from switching
+        // cameras (e.g. back to front camera, and vice versa).
+        if (topActivity == null || !mCameraStateMonitor.isCameraRunningForActivity(topActivity)) {
+            // Call after getTopActivity(), as that method might use the activity from mCameraTask.
+            mCameraTask = null;
+        }
+
+        if (topActivity == null) {
+            return;
+        }
 
         ProtoLog.v(WM_DEBUG_ORIENTATION,
                 "Display id=%d is notified that Camera is closed, updating rotation.",
@@ -406,11 +418,10 @@
         // Checking whether an activity in fullscreen rather than the task as this camera compat
         // treatment doesn't cover activity embedding.
         if (topActivity.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
-            return true;
+            return;
         }
         recomputeConfigurationForCameraCompatIfNeeded(topActivity);
         mDisplayContent.updateOrientation();
-        return true;
     }
 
     // TODO(b/336474959): Do we need cameraId here?
@@ -430,6 +441,16 @@
         }
     }
 
+    @Nullable
+    private ActivityRecord getTopActivity() {
+        if (Flags.cameraCompatFullscreenPickSameTaskActivity()) {
+            return mCameraTask != null ? mCameraTask.getTopActivity(
+                    /* includeFinishing= */ true, /* includeOverlays= */ false) : null;
+        } else {
+            return mDisplayContent.topRunningActivity(/* considerKeyguardState= */ true);
+        }
+    }
+
     /**
      * @return {@code true} if the configuration needs to be recomputed after a camera state update.
      */
diff --git a/services/core/java/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicy.java
index 094434d..046ed61 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicy.java
@@ -17,10 +17,13 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
 
+import static com.android.server.policy.WindowManagerPolicy.USER_ROTATION_FREE;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.res.Configuration.Orientation;
@@ -66,6 +69,37 @@
     }
 
     /**
+     * Returns {@code true} if the orientation update should be skipped and it will update when
+     * transition is done. This is to keep the orientation which was preserved by
+     * {@link #isRotationLockEnforced} from being changed by a transient launch (i.e. recents).
+     */
+    boolean deferOrientationUpdate() {
+        if (mDisplayRotation.getUserRotation() != USER_ROTATION_FREE
+                || mDisplayRotation.getLastOrientation() != SCREEN_ORIENTATION_UNSPECIFIED) {
+            return false;
+        }
+        final WindowOrientationListener orientationListener =
+                mDisplayRotation.getOrientationListener();
+        if (orientationListener == null
+                || orientationListener.getProposedRotation() == mDisplayRotation.getRotation()) {
+            return false;
+        }
+        // The above conditions mean that isRotationLockEnforced might have taken effect:
+        // Auto-rotation is enabled and the proposed rotation is not applied.
+        // Then the update should defer until the transition idle to avoid disturbing animation.
+        if (!mDisplayContent.mTransitionController.hasTransientLaunch(mDisplayContent)) {
+            return false;
+        }
+        mDisplayContent.mTransitionController.mStateValidators.add(() -> {
+            if (!isRotationLockEnforcedLocked(orientationListener.getProposedRotation())) {
+                mDisplayContent.mWmService.updateRotation(false /* alwaysSendConfiguration */,
+                        false /* forceRelayout */);
+            }
+        });
+        return true;
+    }
+
+    /**
      * Decides whether it is necessary to lock screen rotation, preventing auto rotation, based on
      * the top activity configuration and proposed screen rotation.
      *
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 49f717e..59a9e85 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -40,6 +40,7 @@
 import android.view.inputmethod.ImeTracker;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.inputmethod.SoftInputShowHideReason;
 import com.android.internal.protolog.ProtoLog;
 
 import java.io.PrintWriter;
@@ -316,15 +317,21 @@
         if (Flags.refactorInsetsController() && target != null) {
             InsetsControlTarget imeControlTarget = getControlTarget();
             if (target != imeControlTarget) {
-                // TODO(b/353463205): start new request here?
+                // TODO(b/353463205): check if fromUser=false is correct here
+                boolean imeVisible = target.isRequestedVisible(WindowInsets.Type.ime());
+                ImeTracker.Token statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+                        ImeTracker.ORIGIN_SERVER,
+                        imeVisible ? SoftInputShowHideReason.SHOW_INPUT_TARGET_CHANGED
+                                : SoftInputShowHideReason.HIDE_INPUT_TARGET_CHANGED,
+                        false /* fromUser */);
                 reportImeInputTargetStateToControlTarget(target, imeControlTarget,
-                        null /* statsToken */);
+                        statsToken);
             }
         }
     }
 
     private void reportImeInputTargetStateToControlTarget(@NonNull InsetsTarget imeInsetsTarget,
-            InsetsControlTarget controlTarget, @Nullable ImeTracker.Token statsToken) {
+            InsetsControlTarget controlTarget, @NonNull ImeTracker.Token statsToken) {
         // In case of the multi window mode, update the requestedVisibleTypes from
         // the controlTarget (=RemoteInsetsControlTarget) via DisplayImeController.
         // Then, trigger onRequestedVisibleTypesChanged for the controlTarget with
@@ -333,7 +340,7 @@
         if (controlTarget != null) {
             ImeTracker.forLogging().onProgress(statsToken,
                     ImeTracker.PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY);
-            controlTarget.setImeInputTargetRequestedVisibility(imeVisible);
+            controlTarget.setImeInputTargetRequestedVisibility(imeVisible, statsToken);
         } else if (imeInsetsTarget instanceof InsetsControlTarget) {
             // In case of a virtual display that cannot show the IME, the
             // controlTarget will be null here, as no controlTarget was set yet. In
@@ -345,13 +352,16 @@
             if (controlTarget != imeInsetsTarget) {
                 ImeTracker.forLogging().onProgress(statsToken,
                         ImeTracker.PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY);
-                controlTarget.setImeInputTargetRequestedVisibility(imeVisible);
+                controlTarget.setImeInputTargetRequestedVisibility(imeVisible, statsToken);
+                // not all virtual displays have an ImeInsetsSourceProvider, so it is not
+                // guaranteed that the IME will be started when the control target reports its
+                // requested visibility back. Thus, invoking the listener here.
+                invokeOnImeRequestedChangedListener(imeInsetsTarget, statsToken);
             } else {
                 ImeTracker.forLogging().onFailed(statsToken,
                         ImeTracker.PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY);
             }
         }
-        invokeOnImeRequestedChangedListener(imeInsetsTarget, statsToken);
     }
 
     // TODO(b/353463205) check callers to see if we can make statsToken @NonNull
@@ -387,9 +397,9 @@
         WindowToken imeToken = mWindowContainer.asWindowState() != null
                 ? mWindowContainer.asWindowState().mToken : null;
         final var rotationController = mDisplayContent.getAsyncRotationController();
-        if ((rotationController != null && rotationController.isTargetToken(imeToken))
-                || (imeToken != null && imeToken.isSelfAnimating(
-                        0 /* flags */, SurfaceAnimator.ANIMATION_TYPE_TOKEN_TRANSFORM))) {
+        if ((rotationController != null && rotationController.isTargetToken(imeToken)) || (
+                imeToken != null && imeToken.isSelfAnimating(0 /* flags */,
+                        SurfaceAnimator.ANIMATION_TYPE_TOKEN_TRANSFORM))) {
             // Skip reporting IME drawn state when the control target is in fixed
             // rotation, AsyncRotationController will report after the animation finished.
             return;
diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java
index 7043aacf..cee4967 100644
--- a/services/core/java/com/android/server/wm/InsetsControlTarget.java
+++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.inputmethodservice.InputMethodService;
 import android.os.IBinder;
@@ -90,8 +91,10 @@
     /**
      * @param visible the requested visibility for the IME, used for
      * {@link com.android.server.wm.DisplayContent.RemoteInsetsControlTarget}
+     * @param statsToken the token tracking the current IME request
      */
-    default void setImeInputTargetRequestedVisibility(boolean visible) {
+    default void setImeInputTargetRequestedVisibility(boolean visible,
+            @NonNull ImeTracker.Token statsToken) {
     }
 
     /** Returns {@code target.getWindow()}, or null if {@code target} is {@code null}. */
diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS
index 2401f90..98521d3 100644
--- a/services/core/java/com/android/server/wm/OWNERS
+++ b/services/core/java/com/android/server/wm/OWNERS
@@ -19,6 +19,8 @@
 wilsonshih@google.com
 jiamingliu@google.com
 pdwilliams@google.com
+charlesccchen@google.com
+marziana@google.com
 
 # Files related to background activity launches
 per-file Background*Start* = set noparent
diff --git a/services/core/java/com/android/server/wm/PageSizeMismatchDialog.java b/services/core/java/com/android/server/wm/PageSizeMismatchDialog.java
new file mode 100644
index 0000000..8c50913
--- /dev/null
+++ b/services/core/java/com/android/server/wm/PageSizeMismatchDialog.java
@@ -0,0 +1,72 @@
+/*
+ * 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.wm;
+
+import static android.text.Html.FROM_HTML_MODE_COMPACT;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.text.Html;
+import android.view.Window;
+import android.view.WindowManager;
+
+import com.android.internal.R;
+
+/**
+ * Show warning dialog when
+ * - Uncompressed libs inside apk are not aligned to page size
+ * - ELF Load segments are not page size aligned
+ * This dialog will be shown everytime when app is launched. Apps can choose to override
+ * by setting compat mode pageSizeCompat="enabled" in manifest or "disabled" to opt out.
+ * Both cases will skip the PageSizeMismatchDialog.
+ *
+ */
+class PageSizeMismatchDialog extends AppWarnings.BaseDialog {
+    PageSizeMismatchDialog(
+            final AppWarnings manager,
+            Context context,
+            ApplicationInfo appInfo,
+            int userId,
+            String warning) {
+        super(manager, context, appInfo.packageName, userId);
+
+        final PackageManager pm = context.getPackageManager();
+        final CharSequence label =
+                appInfo.loadSafeLabel(
+                        pm,
+                        PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
+                        PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE
+                                | PackageItemInfo.SAFE_LABEL_FLAG_TRIM);
+
+        final AlertDialog.Builder builder =
+                new AlertDialog.Builder(context)
+                        .setPositiveButton(
+                                R.string.ok,
+                                (dialog, which) -> {/* Do nothing */})
+                        .setMessage(Html.fromHtml(warning, FROM_HTML_MODE_COMPACT))
+                        .setTitle(label);
+
+        mDialog = builder.create();
+        mDialog.create();
+
+        final Window window = mDialog.getWindow();
+        window.setType(WindowManager.LayoutParams.TYPE_PHONE);
+    }
+}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index f0e12fe..27f82d9 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -495,11 +495,18 @@
         mTaskNotificationController.notifyTaskListUpdated();
     }
 
-    private void notifyTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess) {
+    private void notifyTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess,
+            boolean removedForAddTask) {
         for (int i = 0; i < mCallbacks.size(); i++) {
             mCallbacks.get(i).onRecentTaskRemoved(task, wasTrimmed, killProcess);
         }
         mTaskNotificationController.notifyTaskListUpdated();
+        if (removedForAddTask) {
+            mTaskNotificationController.notifyRecentTaskRemovedForAddTask(task.mTaskId);
+        }
+    }
+    private void notifyTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess) {
+        notifyTaskRemoved(task, wasTrimmed, killProcess, false /* removedForAddTask */);
     }
 
     /**
@@ -1635,7 +1642,8 @@
                 // from becoming dangling.
                 mHiddenTasks.add(0, removedTask);
             }
-            notifyTaskRemoved(removedTask, false /* wasTrimmed */, false /* killProcess */);
+            notifyTaskRemoved(removedTask, false /* wasTrimmed */, false /* killProcess */,
+                    true /* removedForAddTask */);
             if (DEBUG_RECENTS_TRIM_TASKS) {
                 Slog.d(TAG, "Trimming task=" + removedTask
                         + " for addition of task=" + task);
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index 70b214c..88e5343 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -361,10 +361,13 @@
         }
 
         // If launched from bubble is specified, then ensure that the caller is system or sysui.
-        if (options.getLaunchedFromBubble() && !isSystemOrSystemUI(callingPid, callingUid)) {
+        if ((options.getLaunchedFromBubble() || options.getTaskAlwaysOnTop())
+                && !isSystemOrSystemUI(callingPid, callingUid)) {
             final String msg = "Permission Denial: starting " + getIntentString(intent)
                     + " from " + callerApp + " (pid=" + callingPid
-                    + ", uid=" + callingUid + ") with launchedFromBubble=true";
+                    + ", uid=" + callingUid + ") with"
+                    + (options.getLaunchedFromBubble() ? " launchedFromBubble=true" : "")
+                    + (options.getTaskAlwaysOnTop() ? " taskAlwaysOnTop=true" : "");
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index 586f3c3..c3649fe 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -62,6 +62,8 @@
     private static final int NOTIFY_TASK_MOVED_TO_BACK_LISTENERS_MSG = 27;
     private static final int NOTIFY_LOCK_TASK_MODE_CHANGED_MSG = 28;
     private static final int NOTIFY_TASK_SNAPSHOT_INVALIDATED_LISTENERS_MSG = 29;
+    private static final int NOTIFY_RECENT_TASK_REMOVED_FOR_ADD_TASK_LISTENERS_MSG = 30;
+
 
     // Delay in notifying task stack change listeners (in millis)
     private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -167,6 +169,10 @@
         l.onRecentTaskListFrozenChanged(m.arg1 != 0);
     };
 
+    private final TaskStackConsumer mNotifyRecentTaskRemovedForAddTask = (l, m) -> {
+        l.onRecentTaskRemovedForAddTask(m.arg1);
+    };
+
     private final TaskStackConsumer mNotifyTaskFocusChanged = (l, m) -> {
         l.onTaskFocusChanged(m.arg1, m.arg2 != 0);
     };
@@ -261,6 +267,9 @@
                 case NOTIFY_TASK_LIST_FROZEN_UNFROZEN_MSG:
                     forAllRemoteListeners(mNotifyTaskListFrozen, msg);
                     break;
+                case NOTIFY_RECENT_TASK_REMOVED_FOR_ADD_TASK_LISTENERS_MSG:
+                    forAllRemoteListeners(mNotifyRecentTaskRemovedForAddTask, msg);
+                    break;
                 case NOTIFY_TASK_FOCUS_CHANGED_MSG:
                     forAllRemoteListeners(mNotifyTaskFocusChanged, msg);
                     break;
@@ -541,6 +550,15 @@
         msg.sendToTarget();
     }
 
+    /** Called when a task is removed from the recent tasks list. */
+    void notifyRecentTaskRemovedForAddTask(int taskId) {
+        final Message msg = mHandler.obtainMessage(
+                NOTIFY_RECENT_TASK_REMOVED_FOR_ADD_TASK_LISTENERS_MSG, taskId,
+                0 /* unused */);
+        forAllLocalListeners(mNotifyRecentTaskRemovedForAddTask, msg);
+        msg.sendToTarget();
+    }
+
     /** @see ITaskStackListener#onTaskFocusChanged(int, boolean) */
     void notifyTaskFocusChanged(int taskId, boolean focused) {
         final Message msg = mHandler.obtainMessage(NOTIFY_TASK_FOCUS_CHANGED_MSG,
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index ce032b4..c77b1d9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -46,7 +46,6 @@
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceControlViewHost;
-import android.view.WindowInfo;
 import android.view.WindowManager.DisplayImePolicy;
 import android.view.inputmethod.ImeTracker;
 import android.window.ScreenCapture;
@@ -158,26 +157,8 @@
      * accessibility changed.
      */
     public interface WindowsForAccessibilityCallback {
-
         /**
-         * Called when the windows for accessibility changed. This is called if
-         * {@link com.android.server.accessibility.Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2} is
-         * false.
-         *
-         * @param forceSend Send the windows for accessibility even if they haven't changed.
-         * @param topFocusedDisplayId The display Id which has the top focused window.
-         * @param topFocusedWindowToken The window token of top focused window.
-         * @param windows The windows for accessibility.
-         */
-        void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId,
-                IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows);
-
-        /**
-         * Called when the windows for accessibility changed. This is called if
-         * {@link com.android.server.accessibility.Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2} is
-         * true.
-         * TODO(b/322444245): Remove screenSize parameter by getting it from
-         *  DisplayManager#getDisplay(int).getRealSize() on the a11y side.
+         * Called when the windows for accessibility changed.
          *
          * @param forceSend Send the windows for accessibility even if they haven't changed.
          * @param topFocusedDisplayId The display Id which has the top focused window.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8268cae..7a53ccf 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3030,8 +3030,8 @@
 
                 mWindowContextListenerController.unregisterWindowContainerListener(clientToken);
 
-                final WindowToken token = wc.asWindowToken();
-                if (token != null && token.isFromClient()) {
+                final WindowToken token = wc != null ? wc.asWindowToken() : null;
+                if (token != null && token.isFromClient() && token.getDisplayContent() != null) {
                     removeWindowToken(token.token, token.getDisplayContent().getDisplayId());
                 }
             }
@@ -4668,21 +4668,25 @@
 
     @EnforcePermission(android.Manifest.permission.MANAGE_APP_TOKENS)
     @Override
-    public void updateDisplayWindowRequestedVisibleTypes(
-            int displayId, @InsetsType int requestedVisibleTypes) {
+    public void updateDisplayWindowRequestedVisibleTypes(int displayId,
+            @InsetsType int requestedVisibleTypes, @Nullable ImeTracker.Token statsToken) {
         updateDisplayWindowRequestedVisibleTypes_enforcePermission();
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
                 final DisplayContent dc = mRoot.getDisplayContent(displayId);
                 if (dc == null || dc.mRemoteInsetsControlTarget == null) {
+                    ImeTracker.forLogging().onFailed(statsToken,
+                            ImeTracker.PHASE_WM_UPDATE_DISPLAY_WINDOW_REQUESTED_VISIBLE_TYPES);
                     return;
                 }
+                ImeTracker.forLogging().onProgress(statsToken,
+                        ImeTracker.PHASE_WM_UPDATE_DISPLAY_WINDOW_REQUESTED_VISIBLE_TYPES);
                 dc.mRemoteInsetsControlTarget.setRequestedVisibleTypes(requestedVisibleTypes);
                 // TODO(b/353463205) the statsToken shouldn't be null as it is used later in the
-                //  IME provider. Check if we have to create a new request here
+                //  IME provider. Check if we have to create a new request here, if null.
                 dc.getInsetsStateController().onRequestedVisibleTypesChanged(
-                        dc.mRemoteInsetsControlTarget, null /* statsToken */);
+                        dc.mRemoteInsetsControlTarget, statsToken);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -10314,7 +10318,7 @@
             mH.post(() -> {
                 Toast.makeText(mContext, Looper.getMainLooper(),
                                 mContext.getString(R.string.screen_not_shared_sensitive_content),
-                                Toast.LENGTH_SHORT)
+                                Toast.LENGTH_LONG)
                         .show();
             });
             // If blocked due to notification protection (null window token) log protection applied
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index fe2bcc7..44f5f51 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -1166,6 +1166,10 @@
                 case "--cameraCompatAspectRatio":
                     runSetCameraCompatAspectRatio(pw);
                     break;
+                case "--isCameraCompatFreeformWindowingTreatmentEnabled":
+                    runSetBooleanFlag(pw, mAppCompatConfiguration
+                            ::setIsCameraCompatFreeformWindowingTreatmentEnabled);
+                    break;
                 default:
                     getErrPrintWriter().println(
                             "Error: Unrecognized letterbox style option: " + arg);
@@ -1260,6 +1264,10 @@
                     case "cameraCompatAspectRatio":
                         mAppCompatConfiguration.resetCameraCompatAspectRatio();
                         break;
+                    case "isCameraCompatFreeformWindowingTreatmentEnabled":
+                        mAppCompatConfiguration
+                                .resetIsCameraCompatFreeformWindowingTreatmentEnabled();
+                        break;
                     default:
                         getErrPrintWriter().println(
                                 "Error: Unrecognized letterbox style option: " + arg);
@@ -1371,6 +1379,7 @@
             mAppCompatConfiguration.resetCameraCompatRefreshEnabled();
             mAppCompatConfiguration.resetCameraCompatRefreshCycleThroughStopEnabled();
             mAppCompatConfiguration.resetCameraCompatAspectRatio();
+            mAppCompatConfiguration.resetIsCameraCompatFreeformWindowingTreatmentEnabled();
         }
     }
 
@@ -1445,6 +1454,10 @@
                     + mAppCompatConfiguration.isUserAppAspectRatioSettingsEnabled());
             pw.println("Is the fullscreen option in user aspect ratio settings enabled: "
                     + mAppCompatConfiguration.isUserAppAspectRatioFullscreenEnabled());
+            pw.println("Default aspect ratio for camera compat freeform: "
+                    + mAppCompatConfiguration.getCameraCompatAspectRatio());
+            pw.println("Is camera compatibility freeform treatment enabled for all apps: "
+                    + mAppCompatConfiguration.isCameraCompatFreeformWindowingTreatmentEnabled());
         }
         return 0;
     }
@@ -1701,10 +1714,13 @@
         pw.println("        happen using the \"stopped -> resumed\" cycle rather than");
         pw.println("        \"paused -> resumed\" cycle.");
         pw.println("      --cameraCompatAspectRatio aspectRatio");
-        pw.println("        Aspect ratio of letterbox for fixed-orientation camera apps, during ");
+        pw.println("        Aspect ratio of letterbox for fixed-orientation camera apps, during");
         pw.println("        freeform camera compat mode. If aspectRatio <= "
                 + AppCompatConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO);
         pw.println("        it will be ignored.");
+        pw.println("      --isCameraCompatFreeformWindowingTreatmentEnabled [true|1|false|0]");
+        pw.println("        Whether camera compat treatment is enabled in freeform mode for all");
+        pw.println("        eligible apps.");
         pw.println("  reset-letterbox-style [aspectRatio|cornerRadius|backgroundType");
         pw.println("      |backgroundColor|wallpaperBlurRadius|wallpaperDarkScrimAlpha");
         pw.println("      |horizontalPositionMultiplier|verticalPositionMultiplier");
@@ -1714,7 +1730,8 @@
         pw.println("      |persistentPositionMultiplierForHorizontalReachability");
         pw.println("      |persistentPositionMultiplierForVerticalReachability");
         pw.println("      |defaultPositionMultiplierForVerticalReachability");
-        pw.println("      |cameraCompatAspectRatio]");
+        pw.println("      |cameraCompatAspectRatio");
+        pw.println("      |isCameraCompatFreeformWindowingTreatmentEnabled]");
         pw.println("    Resets overrides to default values for specified properties separated");
         pw.println("    by space, e.g. 'reset-letterbox-style aspectRatio cornerRadius'.");
         pw.println("    If no arguments provided, all values will be reset.");
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index eaa3a37..4c0cee4 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -38,7 +38,6 @@
         "com_android_server_adb_AdbDebuggingManager.cpp",
         "com_android_server_am_BatteryStatsService.cpp",
         "com_android_server_biometrics_SurfaceToNativeHandleConverter.cpp",
-        "com_android_server_ConsumerIrService.cpp",
         "com_android_server_companion_virtual_InputController.cpp",
         "com_android_server_companion_virtual_VirtualDeviceImpl.cpp",
         "com_android_server_devicepolicy_CryptoTestHelper.cpp",
@@ -63,7 +62,6 @@
         "com_android_server_SystemServer.cpp",
         "com_android_server_tv_TvUinputBridge.cpp",
         "com_android_server_tv_TvInputHal.cpp",
-        "com_android_server_vr_VrManagerService.cpp",
         "com_android_server_UsbAlsaJackDetector.cpp",
         "com_android_server_UsbAlsaMidiDevice.cpp",
         "com_android_server_UsbDeviceManager.cpp",
@@ -75,14 +73,13 @@
         "com_android_server_am_LowMemDetector.cpp",
         "com_android_server_pm_PackageManagerShellCommandDataLoader.cpp",
         "com_android_server_sensor_SensorService.cpp",
-        "com_android_server_utils_LazyJniRegistrar.cpp",
         "com_android_server_wm_TaskFpsCallbackController.cpp",
         "onload.cpp",
         ":lib_cachedAppOptimizer_native",
         ":lib_freezer_native",
-        ":lib_gameManagerService_native",
         ":lib_oomConnection_native",
         ":lib_anrTimer_native",
+        ":lib_lazilyRegisteredServices_native",
     ],
 
     include_dirs: [
@@ -248,13 +245,6 @@
 }
 
 filegroup {
-    name: "lib_gameManagerService_native",
-    srcs: [
-        "com_android_server_app_GameManagerService.cpp",
-    ],
-}
-
-filegroup {
     name: "lib_oomConnection_native",
     srcs: ["com_android_server_am_OomConnection.cpp"],
 }
@@ -265,3 +255,13 @@
         "com_android_server_utils_AnrTimer.cpp",
     ],
 }
+
+filegroup {
+    name: "lib_lazilyRegisteredServices_native",
+    srcs: [
+        "com_android_server_ConsumerIrService.cpp",
+        "com_android_server_app_GameManagerService.cpp",
+        "com_android_server_utils_LazyJniRegistrar.cpp",
+        "com_android_server_vr_VrManagerService.cpp",
+    ],
+}
diff --git a/services/core/jni/com_android_server_utils_LazyJniRegistrar.cpp b/services/core/jni/com_android_server_utils_LazyJniRegistrar.cpp
index ad7781e..0c0f8b0 100644
--- a/services/core/jni/com_android_server_utils_LazyJniRegistrar.cpp
+++ b/services/core/jni/com_android_server_utils_LazyJniRegistrar.cpp
@@ -22,6 +22,7 @@
 
 // Forward declared per-class registration methods.
 int register_android_server_ConsumerIrService(JNIEnv* env);
+int register_android_server_app_GameManagerService(JNIEnv* env);
 int register_android_server_vr_VrManagerService(JNIEnv* env);
 
 namespace {
@@ -33,12 +34,17 @@
     register_android_server_ConsumerIrService(env);
 }
 
+void registerGameManagerService(JNIEnv* env, jclass) {
+    register_android_server_app_GameManagerService(env);
+}
+
 void registerVrManagerService(JNIEnv* env, jclass) {
     register_android_server_vr_VrManagerService(env);
 }
 
 static const JNINativeMethod sJniRegistrarMethods[] = {
         {"registerConsumerIrService", "()V", (void*)registerConsumerIrService},
+        {"registerGameManagerService", "()V", (void*)registerGameManagerService},
         {"registerVrManagerService", "()V", (void*)registerVrManagerService},
 };
 
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index c170ae9..df37ec3 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -65,7 +65,6 @@
 int register_android_server_sensor_SensorService(JavaVM* vm, JNIEnv* env);
 int register_android_server_companion_virtual_InputController(JNIEnv* env);
 int register_android_server_companion_virtual_VirtualDeviceImpl(JNIEnv* env);
-int register_android_server_app_GameManagerService(JNIEnv* env);
 int register_com_android_server_wm_TaskFpsCallbackController(JNIEnv* env);
 int register_com_android_server_display_DisplayControl(JNIEnv* env);
 int register_com_android_server_SystemClockTime(JNIEnv* env);
@@ -131,7 +130,6 @@
     register_android_server_sensor_SensorService(vm, env);
     register_android_server_companion_virtual_InputController(env);
     register_android_server_companion_virtual_VirtualDeviceImpl(env);
-    register_android_server_app_GameManagerService(env);
     register_com_android_server_wm_TaskFpsCallbackController(env);
     register_com_android_server_display_DisplayControl(env);
     register_com_android_server_SystemClockTime(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index cb333f0..1c8d06e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -152,19 +152,20 @@
         mAdminPolicySize = new SparseArray<>();
     }
 
-    private void maybeForceEnforcementRefreshLocked(@NonNull PolicyDefinition<?> policyDefinition) {
+    private void forceEnforcementRefreshIfUserRestrictionLocked(
+            @NonNull PolicyDefinition<?> policyDefinition) {
         try {
-            if (shouldForceEnforcementRefresh(policyDefinition)) {
+            if (isUserRestrictionPolicy(policyDefinition)) {
                 // This is okay because it's only true for user restrictions which are all <Boolean>
                 forceEnforcementRefreshLocked((PolicyDefinition<Boolean>) policyDefinition);
             }
         } catch (Throwable e) {
             // Catch any possible exceptions just to be on the safe side
-            Log.e(TAG, "Exception throw during maybeForceEnforcementRefreshLocked", e);
+            Log.e(TAG, "Exception thrown during forceEnforcementRefreshIfUserRestrictionLocked", e);
         }
     }
 
-    private boolean shouldForceEnforcementRefresh(@NonNull PolicyDefinition<?> policyDefinition) {
+    private boolean isUserRestrictionPolicy(@NonNull PolicyDefinition<?> policyDefinition) {
         // These are all "not nullable" but for the purposes of maximum safety for a lightly tested
         // change we check here
         if (policyDefinition == null) {
@@ -257,7 +258,7 @@
             // No need to notify admins as no new policy is actually enforced, we're just filling in
             // the data structures.
             if (!skipEnforcePolicy) {
-                maybeForceEnforcementRefreshLocked(policyDefinition);
+                forceEnforcementRefreshIfUserRestrictionLocked(policyDefinition);
                 if (policyChanged) {
                     onLocalPolicyChangedLocked(policyDefinition, enforcingAdmin, userId);
                 }
@@ -347,7 +348,7 @@
         Objects.requireNonNull(enforcingAdmin);
 
         synchronized (mLock) {
-            maybeForceEnforcementRefreshLocked(policyDefinition);
+            forceEnforcementRefreshIfUserRestrictionLocked(policyDefinition);
             if (!hasLocalPolicyLocked(policyDefinition, userId)) {
                 return;
             }
@@ -517,7 +518,7 @@
             // No need to notify admins as no new policy is actually enforced, we're just filling in
             // the data structures.
             if (!skipEnforcePolicy) {
-                maybeForceEnforcementRefreshLocked(policyDefinition);
+                forceEnforcementRefreshIfUserRestrictionLocked(policyDefinition);
                 if (policyChanged) {
                     onGlobalPolicyChangedLocked(policyDefinition, enforcingAdmin);
                 }
@@ -570,7 +571,7 @@
 
             boolean policyChanged = policyState.removePolicy(enforcingAdmin);
 
-            maybeForceEnforcementRefreshLocked(policyDefinition);
+            forceEnforcementRefreshIfUserRestrictionLocked(policyDefinition);
             if (policyChanged) {
                 onGlobalPolicyChangedLocked(policyDefinition, enforcingAdmin);
             }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index dde213d..6f0d26a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -23178,6 +23178,10 @@
                 MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
         CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_KEYGUARD,
                 MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
+        if (Flags.lockNowCoexistence()) {
+            CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCK,
+                    MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
+        }
         CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
                 MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
 
@@ -23252,8 +23256,10 @@
                 MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
         CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCATION,
                 MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
-        CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCK,
-                MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+        if (!Flags.lockNowCoexistence()) {
+            CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCK,
+                    MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+        }
         CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCK_TASK,
                 MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
         CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MODIFY_USERS,
@@ -23708,24 +23714,7 @@
     }
 
     public void setMtePolicy(int flags, String callerPackageName) {
-        final Set<Integer> allowedModes =
-                Set.of(
-                        DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY,
-                        DevicePolicyManager.MTE_DISABLED,
-                        DevicePolicyManager.MTE_ENABLED);
-        Preconditions.checkArgument(
-                allowedModes.contains(flags), "Provided mode is not one of the allowed values.");
-        // In general, this API should be available when "bootctl_settings_toggle" is set, which
-        // signals that there is a control for MTE in the user settings and this API fundamentally
-        // is a way for the device admin to override that setting.
-        // Allow bootctl_device_policy_manager as an override, e.g. to offer the
-        // DevicePolicyManager only without a visible user setting.
-        if (!mInjector.systemPropertiesGetBoolean(
-                "ro.arm64.memtag.bootctl_device_policy_manager",
-                mInjector.systemPropertiesGetBoolean(
-                        "ro.arm64.memtag.bootctl_settings_toggle", false))) {
-            throw new UnsupportedOperationException("device does not support MTE");
-        }
+        checkMteSupportedAndAllowedPolicy(flags);
         final CallerIdentity caller = getCallerIdentity(callerPackageName);
         // For now we continue to restrict the DISABLED setting to device owner - we might need
         // another permission for this in future.
@@ -23783,6 +23772,53 @@
     }
 
     @Override
+    public void setMtePolicyBySystem(
+            @NonNull String systemEntity, int policy) {
+        Objects.requireNonNull(systemEntity);
+        checkMteSupportedAndAllowedPolicy(policy);
+
+        Preconditions.checkCallAuthorization(isSystemUid(getCallerIdentity()),
+                "Only system services can call setMtePolicyBySystem");
+
+        if (!Flags.setMtePolicyCoexistence()) {
+            throw new UnsupportedOperationException("System can not set MTE policy only");
+        }
+
+        EnforcingAdmin admin = EnforcingAdmin.createSystemEnforcingAdmin(systemEntity);
+        if (policy != DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY) {
+            mDevicePolicyEngine.setGlobalPolicy(
+                    PolicyDefinition.MEMORY_TAGGING,
+                    admin,
+                    new IntegerPolicyValue(policy));
+        } else {
+            mDevicePolicyEngine.removeGlobalPolicy(
+                    PolicyDefinition.MEMORY_TAGGING,
+                    admin);
+        }
+    }
+
+    private void checkMteSupportedAndAllowedPolicy(int policy) {
+        final Set<Integer> allowedModes =
+                Set.of(
+                        DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY,
+                        DevicePolicyManager.MTE_DISABLED,
+                        DevicePolicyManager.MTE_ENABLED);
+        Preconditions.checkArgument(
+                allowedModes.contains(policy), "Provided mode is not one of the allowed values.");
+        // In general, this API should be available when "bootctl_settings_toggle" is set, which
+        // signals that there is a control for MTE in the user settings and this API fundamentally
+        // is a way for the device admin to override that setting.
+        // Allow bootctl_device_policy_manager as an override, e.g. to offer the
+        // DevicePolicyManager only without a visible user setting.
+        if (!mInjector.systemPropertiesGetBoolean(
+                "ro.arm64.memtag.bootctl_device_policy_manager",
+                mInjector.systemPropertiesGetBoolean(
+                        "ro.arm64.memtag.bootctl_settings_toggle", false))) {
+            throw new UnsupportedOperationException("device does not support MTE");
+        }
+    }
+
+    @Override
     public int getMtePolicy(String callerPackageName) {
         final CallerIdentity caller = getCallerIdentity(callerPackageName);
         if (Flags.setMtePolicyCoexistence()) {
@@ -24161,6 +24197,7 @@
         String supervisionBackupId = "36.2.supervision-support";
         boolean supervisionMigrated = maybeMigrateResetPasswordTokenLocked(supervisionBackupId);
         supervisionMigrated |= maybeMigrateSuspendedPackagesLocked(supervisionBackupId);
+        supervisionMigrated |= maybeMigrateSetKeyguardDisabledFeatures(supervisionBackupId);
         if (supervisionMigrated) {
             Slogf.i(LOG_TAG, "Backup made: " + supervisionBackupId);
         }
@@ -24174,6 +24211,38 @@
         // Additional migration steps should repeat the pattern above with a new backupId.
     }
 
+    @GuardedBy("getLockObject()")
+    private boolean maybeMigrateSetKeyguardDisabledFeatures(String backupId) {
+        Slog.i(LOG_TAG, "Migrating set keyguard disabled features to policy engine");
+        if (!Flags.setKeyguardDisabledFeaturesCoexistence()) {
+            return false;
+        }
+        if (mOwners.isSetKeyguardDisabledFeaturesMigrated()) {
+            return false;
+        }
+        // Create backup if none exists
+        mDevicePolicyEngine.createBackup(backupId);
+        try {
+            iterateThroughDpcAdminsLocked((admin, enforcingAdmin) -> {
+                if (admin.disabledKeyguardFeatures == 0) {
+                    return;
+                }
+                int userId = enforcingAdmin.getUserId();
+                mDevicePolicyEngine.setLocalPolicy(
+                        PolicyDefinition.KEYGUARD_DISABLED_FEATURES,
+                        enforcingAdmin,
+                        new IntegerPolicyValue(admin.disabledKeyguardFeatures),
+                        userId);
+            });
+        } catch (Exception e) {
+            Slog.wtf(LOG_TAG, "Failed to migrate set keyguard disabled to policy engine", e);
+        }
+
+        Slog.i(LOG_TAG, "Marking set keyguard disabled features migration complete");
+        mOwners.markSetKeyguardDisabledFeaturesMigrated();
+        return true;
+    }
+
     private void migratePermissionGrantStatePolicies() {
         Slogf.i(LOG_TAG, "Migrating PERMISSION_GRANT policy to device policy engine.");
         for (UserInfo userInfo : mUserManager.getUsers()) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index be4eea4..1c75f2f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -695,6 +695,19 @@
         }
     }
 
+    void markSetKeyguardDisabledFeaturesMigrated() {
+        synchronized (mData) {
+            mData.mSetKeyguardDisabledFeaturesMigrated = true;
+            mData.writeDeviceOwner();
+        }
+    }
+
+    boolean isSetKeyguardDisabledFeaturesMigrated() {
+        synchronized (mData) {
+            return mData.mSetKeyguardDisabledFeaturesMigrated;
+        }
+    }
+
     @GuardedBy("mData")
     void pushToAppOpsLocked() {
         if (!mSystemReady) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
index 1cae924..caaf096 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
@@ -95,6 +95,8 @@
             "resetPasswordWithTokenMigrated";
     private static final String ATTR_MEMORY_TAGGING_MIGRATED =
             "memoryTaggingMigrated";
+    private static final String ATTR_SET_KEYGUARD_DISABLED_FEATURES_MIGRATED =
+            "setKeyguardDisabledFeaturesMigrated";
 
     private static final String ATTR_MIGRATED_POST_UPGRADE = "migratedPostUpgrade";
 
@@ -129,6 +131,7 @@
     boolean mSuspendedPackagesMigrated = false;
     boolean mResetPasswordWithTokenMigrated = false;
     boolean mMemoryTaggingMigrated = false;
+    boolean mSetKeyguardDisabledFeaturesMigrated = false;
 
     boolean mPoliciesMigratedPostUpdate = false;
 
@@ -434,6 +437,10 @@
                 out.attributeBoolean(null, ATTR_MEMORY_TAGGING_MIGRATED,
                         mMemoryTaggingMigrated);
             }
+            if (Flags.setKeyguardDisabledFeaturesCoexistence()) {
+                out.attributeBoolean(null, ATTR_SET_KEYGUARD_DISABLED_FEATURES_MIGRATED,
+                        mSetKeyguardDisabledFeaturesMigrated);
+            }
             out.endTag(null, TAG_POLICY_ENGINE_MIGRATION);
 
         }
@@ -510,6 +517,10 @@
                     mMemoryTaggingMigrated = Flags.setMtePolicyCoexistence()
                             && parser.getAttributeBoolean(null,
                             ATTR_MEMORY_TAGGING_MIGRATED, false);
+                    mSetKeyguardDisabledFeaturesMigrated =
+                            Flags.setKeyguardDisabledFeaturesCoexistence()
+                                    && parser.getAttributeBoolean(null,
+                                    ATTR_SET_KEYGUARD_DISABLED_FEATURES_MIGRATED, false);
                     break;
                 default:
                     Slog.e(TAG, "Unexpected tag: " + tag);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 82d49fc..fde6ce2 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import static android.media.tv.flags.Flags.mediaQualityFw;
 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
@@ -422,6 +423,8 @@
             "com.android.server.wifi.aware.WifiAwareService";
     private static final String WIFI_P2P_SERVICE_CLASS =
             "com.android.server.wifi.p2p.WifiP2pService";
+    private static final String WIFI_USD_SERVICE_CLASS =
+            "com.android.server.wifi.usd.UsdService";
     private static final String CONNECTIVITY_SERVICE_APEX_PATH =
             "/apex/com.android.tethering/javalib/service-connectivity.jar";
     private static final String CONNECTIVITY_SERVICE_INITIALIZER_CLASS =
@@ -2145,6 +2148,13 @@
                 mSystemServiceManager.startServiceFromJar(
                         WIFI_SCANNING_SERVICE_CLASS, WIFI_APEX_SERVICE_JAR_PATH);
                 t.traceEnd();
+                // Start USD service
+                if (android.net.wifi.flags.Flags.usd()) {
+                    t.traceBegin("StartUsd");
+                    mSystemServiceManager.startServiceFromJar(
+                            WIFI_USD_SERVICE_CLASS, WIFI_APEX_SERVICE_JAR_PATH);
+                    t.traceEnd();
+                }
             }
 
             if (context.getPackageManager().hasSystemFeature(
@@ -2607,9 +2617,11 @@
                 t.traceEnd();
             }
 
-            t.traceBegin("StartMediaQuality");
-            mSystemServiceManager.startService(MediaQualityService.class);
-            t.traceEnd();
+            if (mediaQualityFw() && isTv) {
+                t.traceBegin("StartMediaQuality");
+                mSystemServiceManager.startService(MediaQualityService.class);
+                t.traceEnd();
+            }
 
             if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)) {
                 t.traceBegin("StartMediaResourceMonitor");
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index e307e52..228e32e 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -70,6 +70,7 @@
     private int mUsageSetting;
     private boolean mUploadEnabled;
 
+    private static boolean sVerityEnforced;
     private boolean mAdbActive;
 
     private IProfCollectd mIProfcollect;
@@ -117,6 +118,13 @@
             mUsageSetting = -1;
         }
 
+        // Check verity, disable profile upload if not enforced.
+        final String verityMode = SystemProperties.get("ro.boot.veritymode");
+        sVerityEnforced = verityMode.equals("enforcing");
+        if (!sVerityEnforced) {
+            Log.d(LOG_TAG, "verity is not enforced: " + verityMode);
+        }
+
         mUploadEnabled =
             context.getResources().getBoolean(R.bool.config_profcollectReportUploaderEnabled);
 
@@ -373,6 +381,10 @@
                 Log.i(LOG_TAG, "Upload is not enabled.");
                 return;
             }
+            if (!sVerityEnforced) {
+                Log.i(LOG_TAG, "Verity is not enforced.");
+                return;
+            }
             Intent intent = new Intent()
                     .setPackage("com.android.shell")
                     .setAction("com.android.shell.action.PROFCOLLECT_UPLOAD")
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 3fdb53f..31f0370 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -289,6 +289,7 @@
         AndroidPackage::getEmergencyInstaller,
         AndroidPackage::isAllowCrossUidActivitySwitchFromBelow,
         AndroidPackage::getIntentMatchingFlags,
+        AndroidPackage::getPageSizeAppCompatFlags,
     )
 
     override fun extraParams() = listOf(
diff --git a/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java b/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
index 9772ef9..5db6a8f 100644
--- a/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
+++ b/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
@@ -145,6 +145,7 @@
 import android.net.ipsec.ike.exceptions.IkeProtocolException;
 import android.net.ipsec.ike.exceptions.IkeTimeoutException;
 import android.net.vcn.VcnTransportInfo;
+import android.net.vcn.util.PersistableBundleUtils;
 import android.net.wifi.WifiInfo;
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
@@ -179,7 +180,6 @@
 import com.android.server.DeviceIdleInternal;
 import com.android.server.IpSecService;
 import com.android.server.VpnTestBase;
-import com.android.server.vcn.util.PersistableBundleUtils;
 
 import org.junit.Before;
 import org.junit.Test;
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 759976f..1b56b3f 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -17,6 +17,7 @@
 package com.android.server.display;
 
 import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY;
+import static android.Manifest.permission.ADD_MIRROR_DISPLAY;
 import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;
 import static android.Manifest.permission.CAPTURE_VIDEO_OUTPUT;
 import static android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS;
@@ -1385,19 +1386,23 @@
     }
 
     /**
-     * Tests that it's not allowed to create an auto-mirror virtual display without
-     * CAPTURE_VIDEO_OUTPUT permission or a virtual device that can mirror displays
+     * Tests that it is not allowed to create an auto-mirror virtual display for a virtual device
+     * without ADD_MIRROR_DISPLAY permission / without the mirror display capability.
      */
     @Test
-    public void createAutoMirrorDisplay_withoutPermissionOrAllowedVirtualDevice_throwsException()
-            throws Exception {
+    public void createAutoMirrorDisplay_withoutPermission_throwsException() throws Exception {
         DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
         DisplayManagerInternal localService = displayManager.new LocalService();
         registerDefaultDisplays(displayManager);
         when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
         IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
         when(virtualDevice.getDeviceId()).thenReturn(1);
-        when(virtualDevice.canCreateMirrorDisplays()).thenReturn(false);
+        if (android.companion.virtualdevice.flags.Flags.enableLimitedVdmRole()) {
+            when(mContext.checkCallingPermission(ADD_MIRROR_DISPLAY))
+                    .thenReturn(PackageManager.PERMISSION_DENIED);
+        } else {
+            when(virtualDevice.canCreateMirrorDisplays()).thenReturn(false);
+        }
         when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
         when(mContext.checkCallingPermission(CAPTURE_VIDEO_OUTPUT)).thenReturn(
                 PackageManager.PERMISSION_DENIED);
@@ -1428,7 +1433,12 @@
         when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
         IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
         when(virtualDevice.getDeviceId()).thenReturn(1);
-        when(virtualDevice.canCreateMirrorDisplays()).thenReturn(true);
+        if (android.companion.virtualdevice.flags.Flags.enableLimitedVdmRole()) {
+            when(mContext.checkCallingPermission(ADD_MIRROR_DISPLAY))
+                    .thenReturn(PackageManager.PERMISSION_GRANTED);
+        } else {
+            when(virtualDevice.canCreateMirrorDisplays()).thenReturn(true);
+        }
         when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
 
         // Create an auto-mirror virtual display using a virtual device.
@@ -1461,7 +1471,12 @@
         when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
         IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
         when(virtualDevice.getDeviceId()).thenReturn(1);
-        when(virtualDevice.canCreateMirrorDisplays()).thenReturn(true);
+        if (android.companion.virtualdevice.flags.Flags.enableLimitedVdmRole()) {
+            when(mContext.checkCallingPermission(ADD_MIRROR_DISPLAY))
+                    .thenReturn(PackageManager.PERMISSION_GRANTED);
+        } else {
+            when(virtualDevice.canCreateMirrorDisplays()).thenReturn(true);
+        }
         when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
 
         // Create an auto-mirror virtual display using a virtual device.
@@ -1528,7 +1543,12 @@
         when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
         IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
         when(virtualDevice.getDeviceId()).thenReturn(1);
-        when(virtualDevice.canCreateMirrorDisplays()).thenReturn(true);
+        if (android.companion.virtualdevice.flags.Flags.enableLimitedVdmRole()) {
+            when(mContext.checkCallingPermission(ADD_MIRROR_DISPLAY))
+                    .thenReturn(PackageManager.PERMISSION_GRANTED);
+        } else {
+            when(virtualDevice.canCreateMirrorDisplays()).thenReturn(true);
+        }
         when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
         when(mContext.checkCallingPermission(ADD_ALWAYS_UNLOCKED_DISPLAY))
                 .thenReturn(PackageManager.PERMISSION_GRANTED);
@@ -1564,7 +1584,12 @@
         when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
         IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
         when(virtualDevice.getDeviceId()).thenReturn(1);
-        when(virtualDevice.canCreateMirrorDisplays()).thenReturn(true);
+        if (android.companion.virtualdevice.flags.Flags.enableLimitedVdmRole()) {
+            when(mContext.checkCallingPermission(ADD_MIRROR_DISPLAY))
+                    .thenReturn(PackageManager.PERMISSION_GRANTED);
+        } else {
+            when(virtualDevice.canCreateMirrorDisplays()).thenReturn(true);
+        }
         when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
 
         // Create an auto-mirror virtual display using a virtual device.
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
index ff652a2..ad30f22 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -17,6 +17,7 @@
 package com.android.server.display;
 
 import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
+import static android.hardware.devicestate.feature.flags.Flags.FLAG_DEVICE_STATE_PROPERTY_MIGRATION;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.DEFAULT_DISPLAY_GROUP;
 import static android.view.Display.FLAG_REAR;
@@ -77,6 +78,9 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.test.TestLooper;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.view.Display;
 import android.view.DisplayAddress;
 import android.view.DisplayInfo;
@@ -144,6 +148,9 @@
 
     @Rule
     public LocalServiceKeeperRule mLocalServiceKeeperRule = new LocalServiceKeeperRule();
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
 
     @Mock LogicalDisplayMapper.Listener mListenerMock;
     @Mock Context mContextMock;
@@ -691,6 +698,7 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(FLAG_DEVICE_STATE_PROPERTY_MIGRATION)
     public void testDeviceShouldNotBeWokenWhenExitingEmulatedState() {
         assertFalse(mLogicalDisplayMapper.shouldDeviceBeWoken(DEVICE_STATE_OPEN,
                 DEVICE_STATE_EMULATED,
diff --git a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
index e0b0fec..3ac7fb0 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
@@ -335,10 +335,6 @@
             @Override
             public void onStopped() {
             }
-
-            @Override
-            public void onRequestedBrightnessChanged(float brightness) {
-            }
         };
     }
 }
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 993569f..0d25426 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -392,3 +392,10 @@
     ],
     include_filters: ["com.android.server.StorageManagerServiceTest"],
 }
+
+test_module_config {
+    name: "FrameworksMockingServicesTests_service_batteryServiceTest",
+    base: "FrameworksMockingServicesTests",
+    test_suites: ["device-tests"],
+    include_filters: ["com.android.server.BatteryServiceTest"],
+}
diff --git a/services/tests/mockingservicestests/jni/Android.bp b/services/tests/mockingservicestests/jni/Android.bp
index 00543a8..94d4b95 100644
--- a/services/tests/mockingservicestests/jni/Android.bp
+++ b/services/tests/mockingservicestests/jni/Android.bp
@@ -22,8 +22,8 @@
     srcs: [
         ":lib_cachedAppOptimizer_native",
         ":lib_freezer_native",
-        ":lib_gameManagerService_native",
         ":lib_oomConnection_native",
+        ":lib_lazilyRegisteredServices_native",
         "onload.cpp",
     ],
 
@@ -54,6 +54,8 @@
         "android.hardware.graphics.bufferqueue@2.0",
         "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.mapper@4.0",
+        "android.hardware.ir@1.0",
+        "android.hardware.vr@1.0",
         "android.hidl.token@1.0-utils",
     ],
 }
diff --git a/services/tests/mockingservicestests/jni/onload.cpp b/services/tests/mockingservicestests/jni/onload.cpp
index cb246d1..9b4c817 100644
--- a/services/tests/mockingservicestests/jni/onload.cpp
+++ b/services/tests/mockingservicestests/jni/onload.cpp
@@ -26,8 +26,8 @@
 namespace android {
 int register_android_server_am_CachedAppOptimizer(JNIEnv* env);
 int register_android_server_am_Freezer(JNIEnv* env);
-int register_android_server_app_GameManagerService(JNIEnv* env);
 int register_android_server_am_OomConnection(JNIEnv* env);
+int register_android_server_utils_LazyJniRegistrar(JNIEnv* env);
 };
 
 using namespace android;
@@ -44,7 +44,7 @@
     ALOG_ASSERT(env, "Could not retrieve the env!");
     register_android_server_am_CachedAppOptimizer(env);
     register_android_server_am_Freezer(env);
-    register_android_server_app_GameManagerService(env);
     register_android_server_am_OomConnection(env);
+    register_android_server_utils_LazyJniRegistrar(env);
     return JNI_VERSION_1_4;
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/BatteryServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/BatteryServiceTest.java
index 5e2f80b..1fbd53a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/BatteryServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/BatteryServiceTest.java
@@ -79,6 +79,8 @@
     private static final int UPDATED_BATTERY_HEALTH = 3;
     private static final int CURRENT_CHARGE_COUNTER = 4680000;
     private static final int UPDATED_CHARGE_COUNTER = 4218000;
+    private static final int CURRENT_MAX_CHARGING_CURRENT = 298125;
+    private static final int UPDATED_MAX_CHARGING_CURRENT = 398125;
     private static final int HANDLER_IDLE_TIME_MS = 5000;
     @Rule
     public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this)
@@ -143,7 +145,7 @@
     @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
     public void onlyVoltageUpdated_lessThenOnePercent_broadcastNotSent() {
         mBatteryService.update(createHealthInfo(VOLTAGE_LESS_THEN_ONE_PERCENT, CURRENT_BATTERY_TEMP,
-                CURRENT_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH));
+                CURRENT_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH, CURRENT_MAX_CHARGING_CURRENT));
 
         waitForHandlerToExecute();
 
@@ -156,7 +158,8 @@
         mBatteryService.update(
                 createHealthInfo(VOLTAGE_MORE_THEN_ONE_PERCENT, CURRENT_BATTERY_TEMP,
                         CURRENT_CHARGE_COUNTER,
-                        CURRENT_BATTERY_HEALTH));
+                        CURRENT_BATTERY_HEALTH,
+                        CURRENT_MAX_CHARGING_CURRENT));
 
         waitForHandlerToExecute();
 
@@ -165,13 +168,17 @@
 
     @Test
     @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
-    public void onlyVoltageUpdated_broadcastSent() {
+    public void voltageUpdated_withUpdateInChargingCurrent_broadcastSent() {
         mBatteryService.mLastBroadcastVoltageUpdateTime = SystemClock.elapsedRealtime() - 20000;
+        long lastChargingCurrentUpdateTime =
+                mBatteryService.mLastBroadcastMaxChargingCurrentUpdateTime;
         mBatteryService.update(createHealthInfo(VOLTAGE_MORE_THEN_ONE_PERCENT, CURRENT_BATTERY_TEMP,
-                CURRENT_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH));
+                CURRENT_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH, UPDATED_MAX_CHARGING_CURRENT));
 
         waitForHandlerToExecute();
 
+        assertTrue(lastChargingCurrentUpdateTime
+                < mBatteryService.mLastBroadcastMaxChargingCurrentUpdateTime);
         verifyNumberOfTimesBroadcastSent(1);
     }
 
@@ -180,7 +187,8 @@
     public void onlyTempUpdated_lessThenOneDegreeCelsius_broadcastNotSent() {
         mBatteryService.update(
                 createHealthInfo(CURRENT_BATTERY_VOLTAGE, TEMP_LESS_THEN_ONE_DEGREE_CELSIUS,
-                        CURRENT_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH));
+                        CURRENT_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH,
+                        CURRENT_MAX_CHARGING_CURRENT));
 
         waitForHandlerToExecute();
 
@@ -191,23 +199,31 @@
     @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
     public void tempUpdated_broadcastSent() {
         long lastVoltageUpdateTime = mBatteryService.mLastBroadcastVoltageUpdateTime;
+        long lastChargingCurrentUpdateTime =
+                mBatteryService.mLastBroadcastMaxChargingCurrentUpdateTime;
         mBatteryService.update(
                 createHealthInfo(VOLTAGE_LESS_THEN_ONE_PERCENT, TEMP_MORE_THEN_ONE_DEGREE_CELSIUS,
-                        UPDATED_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH));
+                        UPDATED_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH,
+                        UPDATED_MAX_CHARGING_CURRENT));
 
         waitForHandlerToExecute();
 
         assertTrue(lastVoltageUpdateTime < mBatteryService.mLastBroadcastVoltageUpdateTime);
+        assertTrue(lastChargingCurrentUpdateTime
+                < mBatteryService.mLastBroadcastMaxChargingCurrentUpdateTime);
         verifyNumberOfTimesBroadcastSent(1);
     }
 
     @Test
     @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
-    public void batteryHealthUpdated_voltageAndTempConst_broadcastSent() {
+    public void batteryHealthUpdated_withOtherExtrasConstant_broadcastSent() {
+        long lastVoltageUpdateTime = mBatteryService.mLastBroadcastVoltageUpdateTime;
+        long lastChargingCurrentUpdateTime =
+                mBatteryService.mLastBroadcastMaxChargingCurrentUpdateTime;
         mBatteryService.update(
-                createHealthInfo(CURRENT_BATTERY_VOLTAGE, CURRENT_BATTERY_TEMP,
+                createHealthInfo(VOLTAGE_LESS_THEN_ONE_PERCENT, CURRENT_BATTERY_TEMP,
                         CURRENT_CHARGE_COUNTER,
-                        UPDATED_BATTERY_HEALTH));
+                        UPDATED_BATTERY_HEALTH, UPDATED_MAX_CHARGING_CURRENT));
 
         waitForHandlerToExecute();
 
@@ -217,10 +233,13 @@
         mBatteryService.update(
                 createHealthInfo(CURRENT_BATTERY_VOLTAGE, CURRENT_BATTERY_TEMP,
                         UPDATED_CHARGE_COUNTER,
-                        UPDATED_BATTERY_HEALTH));
+                        UPDATED_BATTERY_HEALTH, CURRENT_MAX_CHARGING_CURRENT));
 
         waitForHandlerToExecute();
 
+        assertTrue(lastVoltageUpdateTime < mBatteryService.mLastBroadcastVoltageUpdateTime);
+        assertTrue(lastChargingCurrentUpdateTime
+                < mBatteryService.mLastBroadcastMaxChargingCurrentUpdateTime);
         verifyNumberOfTimesBroadcastSent(1);
     }
 
@@ -228,7 +247,7 @@
     @DisableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
     public void voltageUpdated_lessThanOnePercent_flagDisabled_broadcastSent() {
         mBatteryService.update(createHealthInfo(VOLTAGE_LESS_THEN_ONE_PERCENT, CURRENT_BATTERY_TEMP,
-                CURRENT_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH));
+                CURRENT_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH, CURRENT_MAX_CHARGING_CURRENT));
 
         waitForHandlerToExecute();
 
@@ -241,7 +260,7 @@
         mBatteryService.update(
                 createHealthInfo(CURRENT_BATTERY_VOLTAGE, CURRENT_BATTERY_TEMP,
                         UPDATED_CHARGE_COUNTER,
-                        CURRENT_BATTERY_HEALTH));
+                        CURRENT_BATTERY_HEALTH, CURRENT_MAX_CHARGING_CURRENT));
 
         waitForHandlerToExecute();
 
@@ -254,7 +273,7 @@
         mBatteryService.update(
                 createHealthInfo(CURRENT_BATTERY_VOLTAGE, TEMP_LESS_THEN_ONE_DEGREE_CELSIUS,
                         UPDATED_CHARGE_COUNTER,
-                        CURRENT_BATTERY_HEALTH));
+                        CURRENT_BATTERY_HEALTH, CURRENT_MAX_CHARGING_CURRENT));
 
         waitForHandlerToExecute();
 
@@ -267,18 +286,51 @@
         mBatteryService.update(
                 createHealthInfo(CURRENT_BATTERY_VOLTAGE, CURRENT_BATTERY_TEMP,
                         UPDATED_CHARGE_COUNTER,
-                        CURRENT_BATTERY_HEALTH));
+                        CURRENT_BATTERY_HEALTH, CURRENT_MAX_CHARGING_CURRENT));
 
         waitForHandlerToExecute();
 
         verifyNumberOfTimesBroadcastSent(1);
     }
 
+    @Test
+    @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
+    public void onlyMaxChargingCurrentUpdated_beforeFiveSeconds_broadcastNotSent() {
+        mBatteryService.update(
+                createHealthInfo(CURRENT_BATTERY_VOLTAGE, CURRENT_BATTERY_TEMP,
+                        CURRENT_CHARGE_COUNTER,
+                        CURRENT_BATTERY_HEALTH,
+                        UPDATED_MAX_CHARGING_CURRENT));
+
+        waitForHandlerToExecute();
+
+        verifyNumberOfTimesBroadcastSent(0);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
+    public void maxChargingCurrentUpdated_afterFiveSeconds_broadcastSent() {
+        mBatteryService.mLastBroadcastMaxChargingCurrentUpdateTime =
+                SystemClock.elapsedRealtime() - 5000;
+        long lastVoltageUpdateTime = mBatteryService.mLastBroadcastVoltageUpdateTime;
+        mBatteryService.update(
+                createHealthInfo(VOLTAGE_MORE_THEN_ONE_PERCENT, CURRENT_BATTERY_TEMP,
+                        CURRENT_CHARGE_COUNTER,
+                        CURRENT_BATTERY_HEALTH,
+                        UPDATED_MAX_CHARGING_CURRENT));
+
+        waitForHandlerToExecute();
+
+        assertTrue(lastVoltageUpdateTime < mBatteryService.mLastBroadcastVoltageUpdateTime);
+        verifyNumberOfTimesBroadcastSent(1);
+    }
+
     private HealthInfo createHealthInfo(
             int batteryVoltage,
             int batteryTemperature,
             int batteryChargeCounter,
-            int batteryHealth) {
+            int batteryHealth,
+            int maxChargingCurrent) {
         HealthInfo h = new HealthInfo();
         h.batteryVoltageMillivolts = batteryVoltage;
         h.batteryTemperatureTenthsCelsius = batteryTemperature;
@@ -287,7 +339,7 @@
         h.batteryHealth = batteryHealth;
         h.batteryPresent = true;
         h.batteryLevel = 100;
-        h.maxChargingCurrentMicroamps = 298125;
+        h.maxChargingCurrentMicroamps = maxChargingCurrent;
         h.batteryCurrentAverageMicroamps = -2812;
         h.batteryCurrentMicroamps = 298125;
         h.maxChargingVoltageMicrovolts = 3000;
@@ -308,7 +360,8 @@
         mBatteryService.update(
                 createHealthInfo(CURRENT_BATTERY_VOLTAGE, CURRENT_BATTERY_TEMP,
                         CURRENT_CHARGE_COUNTER,
-                        CURRENT_BATTERY_HEALTH));
+                        CURRENT_BATTERY_HEALTH,
+                        CURRENT_MAX_CHARGING_CURRENT));
 
         waitForHandlerToExecute();
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index ace6aae..6defadf 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -47,8 +47,10 @@
 import static com.android.server.am.ProcessList.NETWORK_STATE_BLOCK;
 import static com.android.server.am.ProcessList.NETWORK_STATE_NO_CHANGE;
 import static com.android.server.am.ProcessList.NETWORK_STATE_UNBLOCK;
+
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -87,6 +89,7 @@
 import android.app.NotificationChannel;
 import android.app.SyncNotedAppOp;
 import android.app.backup.BackupAnnotations;
+import android.content.ClipData;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -98,6 +101,7 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ServiceInfo;
+import android.graphics.Rect;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Bundle;
@@ -105,6 +109,7 @@
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.IProgressListener;
+import android.os.IpcDataCache;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
@@ -201,6 +206,16 @@
 
     private static final String TEST_AUTHORITY = "test_authority";
     private static final String TEST_MIME_TYPE = "application/test_type";
+    private static final Uri TEST_URI = Uri.parse("content://com.example/people");
+    private static final int TEST_CREATOR_UID = 12345;
+    private static final String TEST_CREATOR_PACKAGE = "android.content.testCreatorPackage";
+    private static final String TEST_TYPE = "testType";
+    private static final String TEST_IDENTIFIER = "testIdentifier";
+    private static final String TEST_CATEGORY = "testCategory";
+    private static final String TEST_LAUNCH_TOKEN = "testLaunchToken";
+    private static final ComponentName TEST_COMPONENT = new ComponentName(TEST_PACKAGE,
+            "TestClass");
+    private static final int ALL_SET_FLAG = 0xFFFFFFFF;
 
     private static final int[] UID_RECORD_CHANGES = {
         UidRecord.CHANGE_PROCSTATE,
@@ -959,28 +974,37 @@
     @Test
     @SuppressWarnings("GuardedBy")
     public void testBroadcastStickyIntent_verifyTypeNotResolved() throws Exception {
-        final Intent intent = new Intent(TEST_ACTION1);
-        final Uri uri = new Uri.Builder()
-                .scheme(SCHEME_CONTENT)
-                .authority(TEST_AUTHORITY)
-                .path("green")
-                .build();
-        intent.setData(uri);
-        broadcastIntent(intent, null, true, TEST_MIME_TYPE, USER_ALL);
-        assertStickyBroadcasts(mAms.getStickyBroadcastsForTest(TEST_ACTION1, USER_ALL),
-                StickyBroadcast.create(intent, false, Process.myUid(), PROCESS_STATE_UNKNOWN,
-                        TEST_MIME_TYPE));
-        when(mContentResolver.getType(uri)).thenReturn(TEST_MIME_TYPE);
+        MockitoSession mockitoSession =
+                ExtendedMockito.mockitoSession().mockStatic(IpcDataCache.class).startMocking();
 
-        addUidRecord(TEST_UID, TEST_PACKAGE);
-        final ProcessRecord procRecord = mAms.getProcessRecordLocked(TEST_PACKAGE, TEST_UID);
-        final IntentFilter intentFilter = new IntentFilter(TEST_ACTION1);
-        intentFilter.addDataType(TEST_MIME_TYPE);
-        final Intent resultIntent = mAms.registerReceiverWithFeature(procRecord.getThread(),
-                TEST_PACKAGE, null, null, null, intentFilter, null, TEST_USER,
-                Context.RECEIVER_EXPORTED);
-        assertNotNull(resultIntent);
-        verify(mContentResolver, never()).getType(any());
+        try {
+            final Intent intent = new Intent(TEST_ACTION1);
+            final Uri uri = new Uri.Builder()
+                    .scheme(SCHEME_CONTENT)
+                    .authority(TEST_AUTHORITY)
+                    .path("green")
+                    .build();
+            intent.setData(uri);
+            broadcastIntent(intent, null, true, TEST_MIME_TYPE, USER_ALL);
+            assertStickyBroadcasts(mAms.getStickyBroadcastsForTest(TEST_ACTION1, USER_ALL),
+                    StickyBroadcast.create(intent, false, Process.myUid(), PROCESS_STATE_UNKNOWN,
+                            TEST_MIME_TYPE));
+            when(mContentResolver.getType(uri)).thenReturn(TEST_MIME_TYPE);
+            ExtendedMockito.doNothing().when(
+                    () -> IpcDataCache.invalidateCache(anyString(), anyString()));
+
+            addUidRecord(TEST_UID, TEST_PACKAGE);
+            final ProcessRecord procRecord = mAms.getProcessRecordLocked(TEST_PACKAGE, TEST_UID);
+            final IntentFilter intentFilter = new IntentFilter(TEST_ACTION1);
+            intentFilter.addDataType(TEST_MIME_TYPE);
+            final Intent resultIntent = mAms.registerReceiverWithFeature(procRecord.getThread(),
+                    TEST_PACKAGE, null, null, null, intentFilter, null, TEST_USER,
+                    Context.RECEIVER_EXPORTED);
+            assertNotNull(resultIntent);
+            verify(mContentResolver, never()).getType(any());
+        } finally {
+            mockitoSession.finishMocking();
+        }
     }
 
     @SuppressWarnings("GuardedBy")
@@ -1402,6 +1426,34 @@
                 & Intent.EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN).isEqualTo(0);
     }
 
+    @Test
+    public void testUseCloneForCreatorTokenAndOriginalIntent_createSameIntentCreatorToken() {
+        Intent testIntent = new Intent(TEST_ACTION1)
+                .setComponent(TEST_COMPONENT)
+                .setDataAndType(TEST_URI, TEST_TYPE)
+                .setIdentifier(TEST_IDENTIFIER)
+                .addCategory(TEST_CATEGORY);
+        testIntent.setOriginalIntent(new Intent(TEST_ACTION2));
+        testIntent.setSelector(new Intent(TEST_ACTION3));
+        testIntent.setSourceBounds(new Rect(0, 0, 100, 100));
+        testIntent.setLaunchToken(TEST_LAUNCH_TOKEN);
+        testIntent.addFlags(ALL_SET_FLAG)
+                .addExtendedFlags(ALL_SET_FLAG);
+        ClipData testClipData = ClipData.newHtmlText("label", "text", "<html/>");
+        testClipData.addItem(new ClipData.Item(new Intent(TEST_ACTION1)));
+        testClipData.addItem(new ClipData.Item(TEST_URI));
+        testIntent.putExtra(TEST_EXTRA_KEY1, TEST_EXTRA_VALUE1);
+
+        ActivityManagerService.IntentCreatorToken tokenForFullIntent =
+                new ActivityManagerService.IntentCreatorToken(TEST_CREATOR_UID,
+                        TEST_CREATOR_PACKAGE, testIntent);
+        ActivityManagerService.IntentCreatorToken tokenForCloneIntent =
+                new ActivityManagerService.IntentCreatorToken(TEST_CREATOR_UID,
+                        TEST_CREATOR_PACKAGE, testIntent.cloneForCreatorToken());
+
+        assertThat(tokenForFullIntent.getKeyFields()).isEqualTo(tokenForCloneIntent.getKeyFields());
+    }
+
     private void verifyWaitingForNetworkStateUpdate(long curProcStateSeq,
             long lastNetworkUpdatedProcStateSeq,
             final long procStateSeqToWait, boolean expectWait) throws Exception {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index a9569b4..1efe470 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -105,6 +105,7 @@
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.util.ArrayMap;
@@ -3260,6 +3261,24 @@
                 "cch-empty");
     }
 
+    @SuppressWarnings("GuardedBy")
+    @Test
+    @EnableFlags(Flags.FLAG_FIX_APPLY_OOMADJ_ORDER)
+    public void testUpdateOomAdj_ApplyOomAdjInCorrectOrder() {
+        final int numberOfApps = 5;
+        final ProcessRecord[] apps = new ProcessRecord[numberOfApps];
+        for (int i = 0; i < numberOfApps; i++) {
+            apps[i] = spy(makeDefaultProcessRecord(MOCKAPP_PID + i, MOCKAPP_UID + i,
+                    MOCKAPP_PROCESSNAME + i, MOCKAPP_PACKAGENAME + i, true));
+        }
+        updateOomAdj(apps);
+        for (int i = 1; i < numberOfApps; i++) {
+            final int pre = mInjector.mSetOomAdjAppliedAt.get(apps[i - 1].mPid);
+            final int cur = mInjector.mSetOomAdjAppliedAt.get(apps[i].mPid);
+            assertTrue("setOomAdj is called in wrong order", pre < cur);
+        }
+    }
+
     private ProcessRecord makeDefaultProcessRecord(int pid, int uid, String processName,
             String packageName, boolean hasShownUi) {
         return new ProcessRecordBuilder(pid, uid, processName, packageName).setHasShownUi(
@@ -3589,9 +3608,16 @@
         long mTimeOffsetMillis = 0;
         private SparseIntArray mLastSetOomAdj = new SparseIntArray();
 
+        // A sequence number that increases every time setOomAdj is called
+        int mLastAppliedAt = 0;
+        // Holds the last sequence number setOomAdj is called for a pid
+        private SparseIntArray mSetOomAdjAppliedAt = new SparseIntArray();
+
         void reset() {
             mTimeOffsetMillis = 0;
             mLastSetOomAdj.clear();
+            mLastAppliedAt = 0;
+            mSetOomAdjAppliedAt.clear();
         }
 
         void jumpUptimeAheadTo(long uptimeMillis) {
@@ -3616,6 +3642,7 @@
                 final int pid = proc.getPid();
                 if (pid <= 0) continue;
                 mLastSetOomAdj.put(pid, proc.mState.getCurAdj());
+                mSetOomAdjAppliedAt.put(pid, mLastAppliedAt++);
             }
         }
 
@@ -3623,6 +3650,7 @@
         void setOomAdj(int pid, int uid, int adj) {
             if (pid <= 0) return;
             mLastSetOomAdj.put(pid, adj);
+            mSetOomAdjAppliedAt.put(pid, mLastAppliedAt++);
         }
 
         @Override
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java b/services/tests/mockingservicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java
index c77ab0f..7454248 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java
@@ -21,10 +21,14 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 
+import static org.mockito.Mockito.verify;
+
 import android.content.ContentResolver;
 import android.os.SystemProperties;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
 
@@ -34,6 +38,7 @@
 import org.junit.Test;
 import org.mockito.Answers;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoSession;
 import org.mockito.quality.Strictness;
 import org.mockito.stubbing.Answer;
@@ -111,6 +116,20 @@
     }
 
     @Test
+    public void testClearAconfigStorageOverride() {
+        SettingsToPropertiesMapper spyMapper = Mockito.spy(new SettingsToPropertiesMapper(
+                mMockContentResolver, TEST_MAPPING, new String[] {}, new String[] {}));
+        HashMap flags = new HashMap();
+        flags.put("test_package.test_flag", null);
+        DeviceConfig.Properties props = new DeviceConfig.Properties("test_namespace", flags);
+
+        spyMapper.setLocalOverridesInNewStorage(props);
+
+        verify(spyMapper).writeFlagOverrideRemovalRequest(new ProtoOutputStream(),
+                "test_package", "test_flag", true);
+    }
+
+    @Test
     public void validateRegisteredGlobalSettings() {
         HashSet<String> hashSet = new HashSet<>();
         for (String globalSetting : SettingsToPropertiesMapper.sGlobalSettings) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/BackupAgentConnectionManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/BackupAgentConnectionManagerTest.java
index 19e43b6..2461e9e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/BackupAgentConnectionManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/BackupAgentConnectionManagerTest.java
@@ -196,6 +196,31 @@
     }
 
     @Test
+    public void bindToAgentSynchronous_unexpectedAgentConnected_doesNotReturnWrongAgent()
+            throws Exception {
+        when(mActivityManager.bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(),
+                anyInt(), anyBoolean())).thenReturn(true);
+        // This is so that IBackupAgent.Stub.asInterface() works.
+        when(mBackupAgentStub.queryLocalInterface(any())).thenReturn(mBackupAgentStub);
+        when(mConnectionManager.getCallingUid()).thenReturn(Process.SYSTEM_UID);
+
+        // This is going to block until it receives the callback so we need to run it on a
+        // separate thread.
+        Thread testThread = new Thread(() -> setBackupAgentResult(
+                mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+                        ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD)),
+                "backup-agent-connection-manager-test");
+        testThread.start();
+        // Give the testThread a head start, otherwise agentConnected() might run before
+        // bindToAgentSynchronous() is called.
+        Thread.sleep(500);
+        mConnectionManager.agentConnected("com.other.package", mBackupAgentStub);
+        testThread.join(100); // Avoid waiting the full timeout.
+
+        assertThat(mBackupAgentResult).isNull();
+    }
+
+    @Test
     @DisableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
     public void bindToAgentSynchronous_restrictedModeChangesFlagOff_shouldUseRestrictedMode()
             throws Exception {
@@ -345,6 +370,7 @@
 
     @Test
     public void agentDisconnected_cancelsCurrentOperations() throws Exception {
+        when(mConnectionManager.getCallingUid()).thenReturn(Process.SYSTEM_UID);
         when(mOperationStorage.operationTokensForPackage(eq(TEST_PACKAGE))).thenReturn(
                 ImmutableSet.of(123, 456, 789));
         when(mConnectionManager.getThreadForCancellation(any())).thenAnswer(invocation -> {
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index dd7ce21..c831475 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.job;
 
+import static android.app.job.Flags.FLAG_HANDLE_ABANDONED_JOBS;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
@@ -82,6 +83,7 @@
 import android.os.SystemClock;
 import android.os.WorkSource;
 import android.os.WorkSource.WorkChain;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.RequiresFlagsDisabled;
 import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
@@ -1056,6 +1058,75 @@
     /**
      * Confirm that
      * {@link JobSchedulerService#getRescheduleJobForFailureLocked(JobStatus, int, int)}
+     * returns a job with the correct delay for abandoned jobs.
+     */
+    @Test
+    @EnableFlags(FLAG_HANDLE_ABANDONED_JOBS)
+    public void testGetRescheduleJobForFailure_abandonedJob() {
+        final long nowElapsed = sElapsedRealtimeClock.millis();
+        final long initialBackoffMs = MINUTE_IN_MILLIS;
+        mService.mConstants.SYSTEM_STOP_TO_FAILURE_RATIO = 3;
+
+        JobStatus originalJob = createJobStatus("testGetRescheduleJobForFailure",
+                createJobInfo()
+                        .setBackoffCriteria(initialBackoffMs, JobInfo.BACKOFF_POLICY_LINEAR));
+        assertEquals(JobStatus.NO_EARLIEST_RUNTIME, originalJob.getEarliestRunTime());
+        assertEquals(JobStatus.NO_LATEST_RUNTIME, originalJob.getLatestRunTimeElapsed());
+
+        // failure = 1, systemStop = 0, abandoned = 1
+        JobStatus rescheduledJob = mService.getRescheduleJobForFailureLocked(originalJob,
+                JobParameters.STOP_REASON_DEVICE_STATE,
+                JobParameters.INTERNAL_STOP_REASON_TIMEOUT_ABANDONED);
+        assertEquals(nowElapsed + initialBackoffMs, rescheduledJob.getEarliestRunTime());
+        assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
+
+        // failure = 2, systemstop = 0, abandoned = 2
+        rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+                JobParameters.STOP_REASON_DEVICE_STATE,
+                JobParameters.INTERNAL_STOP_REASON_TIMEOUT_ABANDONED);
+        assertEquals(nowElapsed + (2 * initialBackoffMs), rescheduledJob.getEarliestRunTime());
+        assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
+
+        // failure = 3, systemstop = 0, abandoned = 3
+        rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+                JobParameters.STOP_REASON_DEVICE_STATE,
+                JobParameters.INTERNAL_STOP_REASON_TIMEOUT_ABANDONED);
+        assertEquals(nowElapsed + (3 * initialBackoffMs), rescheduledJob.getEarliestRunTime());
+        assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
+
+        // failure = 4, systemstop = 0, abandoned = 4
+        rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+                JobParameters.STOP_REASON_DEVICE_STATE,
+                JobParameters.INTERNAL_STOP_REASON_TIMEOUT_ABANDONED);
+        assertEquals(
+                nowElapsed + ((long) Math.scalb((float) initialBackoffMs, 3)),
+                rescheduledJob.getEarliestRunTime());
+        assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
+
+        // failure = 4, systemstop = 1, abandoned = 4
+        rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+                JobParameters.STOP_REASON_DEVICE_STATE,
+                JobParameters.INTERNAL_STOP_REASON_DEVICE_THERMAL);
+        assertEquals(
+                nowElapsed + ((long) Math.scalb((float) initialBackoffMs, 3)),
+                rescheduledJob.getEarliestRunTime());
+        assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
+
+        // failure = 4, systemStop =  4  / SYSTEM_STOP_TO_FAILURE_RATIO, abandoned = 4
+        for (int i = 0; i < mService.mConstants.SYSTEM_STOP_TO_FAILURE_RATIO; ++i) {
+            rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+                    JobParameters.STOP_REASON_SYSTEM_PROCESSING,
+                    JobParameters.INTERNAL_STOP_REASON_RTC_UPDATED);
+        }
+        assertEquals(
+                nowElapsed + ((long) Math.scalb((float) initialBackoffMs, 4)),
+                rescheduledJob.getEarliestRunTime());
+        assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
+    }
+
+    /**
+     * Confirm that
+     * {@link JobSchedulerService#getRescheduleJobForFailureLocked(JobStatus, int, int)}
      * returns a job that is correctly marked as demoted by the user.
      */
     @Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java
index c6a6865..c64973a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java
@@ -706,14 +706,14 @@
                 // "True" start is nowElapsed + HOUR_IN_MILLIS
                 nowElapsed + HOUR_IN_MILLIS + adjustmentMs,
                 nowElapsed + 2 * HOUR_IN_MILLIS,
-                0 /* numFailures */, 0 /* numSystemStops */,
+                0 /* numFailures */, 0 /* numAbandonedFailures */, 0 /* numSystemStops */,
                 JobSchedulerService.sSystemClock.millis() /* lastSuccessfulRunTime */,
                 0, 0);
         jsFlex = new JobStatus(jsFlex,
                 // "True" start is nowElapsed + 2 * HOUR_IN_MILLIS - 20 * MINUTE_IN_MILLIS
                 nowElapsed + 2 * HOUR_IN_MILLIS - 20 * MINUTE_IN_MILLIS + adjustmentMs,
                 nowElapsed + 2 * HOUR_IN_MILLIS,
-                0 /* numFailures */, 0 /* numSystemStops */,
+                0 /* numFailures */, 0 /* numAbandonedFailures */, 0 /* numSystemStops */,
                 JobSchedulerService.sSystemClock.millis() /* lastSuccessfulRunTime */,
                 0, 0);
 
@@ -726,13 +726,13 @@
         jsBasic = new JobStatus(jsBasic,
                 nowElapsed + 30 * MINUTE_IN_MILLIS,
                 NO_LATEST_RUNTIME,
-                1 /* numFailures */, 1 /* numSystemStops */,
+                1 /* numFailures */, 0 /* numAbandonedFailures */, 1 /* numSystemStops */,
                 JobSchedulerService.sSystemClock.millis() /* lastSuccessfulRunTime */,
                 0, 0);
         jsFlex = new JobStatus(jsFlex,
                 nowElapsed + 30 * MINUTE_IN_MILLIS,
                 NO_LATEST_RUNTIME,
-                1 /* numFailures */, 1 /* numSystemStops */,
+                1 /* numFailures */, 0 /* numAbandonedFailures */, 1 /* numSystemStops */,
                 JobSchedulerService.sSystemClock.millis() /* lastSuccessfulRunTime */,
                 0, 0);
 
@@ -847,21 +847,24 @@
         JobInfo.Builder jb = createJob(0).setOverrideDeadline(HOUR_IN_MILLIS);
         JobStatus js = createJobStatus("time", jb);
         js = new JobStatus(
-                js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 2, /* numSystemStops */ 0,
+                js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 2,
+                0 /* numAbandonedFailures */, /* numSystemStops */ 0,
                 0, FROZEN_TIME, FROZEN_TIME);
 
         assertEquals(mFcConfig.RESCHEDULED_JOB_DEADLINE_MS,
                 mFlexibilityController.getLifeCycleEndElapsedLocked(js, nowElapsed, 0));
 
         js = new JobStatus(
-                js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 2, /* numSystemStops */ 1,
+                js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 2,
+                0 /* numAbandonedFailures */, /* numSystemStops */ 1,
                 0, FROZEN_TIME, FROZEN_TIME);
 
         assertEquals(2 * mFcConfig.RESCHEDULED_JOB_DEADLINE_MS,
                 mFlexibilityController.getLifeCycleEndElapsedLocked(js, nowElapsed, 0));
 
         js = new JobStatus(
-                js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 0, /* numSystemStops */ 10,
+                js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 0,
+                0 /* numAbandonedFailures */, /* numSystemStops */ 10,
                 0, FROZEN_TIME, FROZEN_TIME);
         assertEquals(mFcConfig.MAX_RESCHEDULED_DEADLINE_MS,
                 mFlexibilityController.getLifeCycleEndElapsedLocked(js, nowElapsed, 0));
@@ -1092,11 +1095,13 @@
         JobInfo.Builder jb = createJob(0);
         JobStatus js = createJobStatus("time", jb);
         js = new JobStatus(
-                js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 1, /* numSystemStops */ 0,
+                js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 1,
+                /* numAbandonedFailures */ 0, /* numSystemStops */ 0,
                 0, FROZEN_TIME, FROZEN_TIME);
         assertFalse(js.hasFlexibilityConstraint());
         js = new JobStatus(
-                js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 0, /* numSystemStops */ 1,
+                js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 0,
+                /* numAbandonedFailures */ 0, /* numSystemStops */ 1,
                 0, FROZEN_TIME, FROZEN_TIME);
         assertFalse(js.hasFlexibilityConstraint());
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index 2d0f4b6..86101cf 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -459,35 +459,35 @@
         int numFailures = 1;
         int numSystemStops = 0;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
 
         // 2+ failures, priority should be lowered as much as possible.
         numFailures = 2;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
         numFailures = 5;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
         numFailures = 8;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
 
         // System stops shouldn't factor in the downgrade.
         numSystemStops = 10;
         numFailures = 0;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
 
         // Less than 2 failures, but job is downgraded.
         numFailures = 1;
         numSystemStops = 0;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         job.addInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_USER);
         assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
     }
@@ -505,44 +505,44 @@
         int numFailures = 1;
         int numSystemStops = 0;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
 
         // Failures in [2,4), priority should be lowered slightly.
         numFailures = 2;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_DEFAULT, job.getEffectivePriority());
         numFailures = 3;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_DEFAULT, job.getEffectivePriority());
 
         // Failures in [4,6), priority should be lowered more.
         numFailures = 4;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
         numFailures = 5;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
 
         // 6+ failures, priority should be lowered as much as possible.
         numFailures = 6;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_MIN, job.getEffectivePriority());
         numFailures = 12;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_MIN, job.getEffectivePriority());
 
         // System stops shouldn't factor in the downgrade.
         numSystemStops = 10;
         numFailures = 0;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
     }
 
@@ -563,32 +563,32 @@
         int numFailures = 1;
         int numSystemStops = 0;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
         numFailures = 4;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
         numFailures = 5;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
 
         // 6+ failures, priority should be lowered as much as possible.
         numFailures = 6;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_MIN, job.getEffectivePriority());
         numFailures = 12;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_MIN, job.getEffectivePriority());
 
         // System stops shouldn't factor in the downgrade.
         numSystemStops = 10;
         numFailures = 0;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
     }
 
@@ -606,28 +606,28 @@
         int numFailures = 1;
         int numSystemStops = 0;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
 
         // 2+ failures, priority shouldn't be affected while job is still a UI job
         numFailures = 2;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
         numFailures = 5;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
         numFailures = 8;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
 
         // System stops shouldn't factor in the downgrade.
         numSystemStops = 10;
         numFailures = 0;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
 
         // Job can no long run as user-initiated. Downgrades should be effective.
@@ -641,28 +641,28 @@
         numFailures = 1;
         numSystemStops = 0;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
 
         // 2+ failures, priority should start getting lower
         numFailures = 2;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_DEFAULT, job.getEffectivePriority());
         numFailures = 5;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
         numFailures = 8;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_MIN, job.getEffectivePriority());
 
         // System stops shouldn't factor in the downgrade.
         numSystemStops = 10;
         numFailures = 0;
         job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
-                numSystemStops, 0, 0, 0);
+                0, numSystemStops, 0, 0, 0);
         assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
     }
 
@@ -772,14 +772,14 @@
         assertTrue(job.shouldTreatAsUserInitiatedJob());
 
         JobStatus rescheduledJob = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME,
-                0, 0, 0, 0, 0);
+                0, 0, 0, 0, 0, 0);
         assertTrue(rescheduledJob.shouldTreatAsUserInitiatedJob());
 
         job.addInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_USER);
         assertFalse(job.shouldTreatAsUserInitiatedJob());
 
         rescheduledJob = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME,
-                0, 0, 0, 0, 0);
+                0, 0, 0, 0, 0, 0);
         assertFalse(rescheduledJob.shouldTreatAsUserInitiatedJob());
 
         rescheduledJob.removeInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_USER);
@@ -797,14 +797,14 @@
         assertTrue(job.shouldTreatAsUserInitiatedJob());
 
         JobStatus rescheduledJob = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME,
-                0, 0, 0, 0, 0);
+                0, 0, 0, 0, 0, 0);
         assertTrue(rescheduledJob.shouldTreatAsUserInitiatedJob());
 
         job.addInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_SYSTEM_UIJ);
         assertFalse(job.shouldTreatAsUserInitiatedJob());
 
         rescheduledJob = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME,
-                0, 0, 0, 0, 0);
+                0, 0, 0, 0, 0, 0);
         assertFalse(rescheduledJob.shouldTreatAsUserInitiatedJob());
 
         rescheduledJob.removeInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_SYSTEM_UIJ);
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/geometry/S2CellIdUtilsTest.java b/services/tests/mockingservicestests/src/com/android/server/location/geometry/S2CellIdUtilsTest.java
new file mode 100644
index 0000000..9e43b81
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/geometry/S2CellIdUtilsTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.location.geometry;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.internal.location.geometry.S2CellIdUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class S2CellIdUtilsTest {
+
+    // S2 cell ID of a level-30 cell in Times Square.
+    private static final long TIMES_SQUARE_S2_ID =
+            S2CellIdUtils.fromLatLngDegrees(40.758896, -73.985130);
+
+    // Position of the Eiffel tower (outside of any parent cell from Times Square).
+    private static final double[] EIFFEL_TOWER_LATLNG = {48.858093, 2.294694};
+
+    // Test vector around TIMES_SQUARE_S2_ID: Cell IDs and the centers for levels 0 to 30.
+    // This test vector has been computed using the public S2 library in
+    // external/s2-geometry-library-java
+    private static final CellAndCenter[] TIMES_SQUARE_CELLS = {
+            new CellAndCenter("9", -0.0, -90.0),
+            new CellAndCenter("8c", 21.037511025421814, -67.38013505195958),
+            new CellAndCenter("89", 34.04786296943431, -79.38034472384487),
+            new CellAndCenter("89c", 38.79459515585768, -73.46516214265485),
+            new CellAndCenter("89d", 41.74704688465104, -76.45630866778862),
+            new CellAndCenter("89c4", 40.29416073145462, -74.96763653470293),
+            new CellAndCenter("89c3", 40.827706513259564, -74.21793256064282),
+            new CellAndCenter("89c24", 40.45771021423038, -73.84190634077625),
+            new CellAndCenter("89c25", 40.64307662867646, -74.03001224983848),
+            new CellAndCenter("89c25c", 40.708880489804564, -73.93598211433742),
+            new CellAndCenter("89c259", 40.75509755935301, -73.9830029344863),
+            new CellAndCenter("89c2584", 40.7781887758716, -74.00650903621303),
+            new CellAndCenter("89c2585", 40.766644611813284, -73.99475634561863),
+            new CellAndCenter("89c25854", 40.76087144655763, -73.98887973002674),
+            new CellAndCenter("89c25855", 40.75798459318946, -73.98594135473846),
+            new CellAndCenter("89c25855c", 40.75901097797799, -73.98447215023141),
+            new CellAndCenter("89c25855b", 40.758497791893824, -73.98520675388987),
+            new CellAndCenter("89c25855bc", 40.75875438651343, -73.98483945241185),
+            new CellAndCenter("89c25855b9", 40.758934819692875, -73.98502310323867),
+            new CellAndCenter("89c25855b9c", 40.75887067137071, -73.98511492858621),
+            new CellAndCenter("89c25855b9d", 40.75891577956465, -73.98516084124353),
+            new CellAndCenter("89c25855b9c4", 40.758893225473194, -73.98513788491626),
+            new CellAndCenter("89c25855b9c7", 40.75890124402366, -73.98512640675159),
+            new CellAndCenter("89c25855b9c6c", 40.758897234748815, -73.985132145834),
+            new CellAndCenter("89c25855b9c6d", 40.75889441548664, -73.98512927629281),
+            new CellAndCenter("89c25855b9c6c4", 40.75889582511775, -73.98513071106342),
+            new CellAndCenter("89c25855b9c6c3", 40.758896326277146, -73.98512999367811),
+            new CellAndCenter("89c25855b9c6c3c", 40.75889607569745, -73.98513035237076),
+            new CellAndCenter("89c25855b9c6c39", 40.75889589949357, -73.98513017302443),
+            new CellAndCenter("89c25855b9c6c39c", 40.75889596213849, -73.98513008335128),
+            new CellAndCenter("89c25855b9c6c39f", 40.75889599346095, -73.9851300385147)};
+
+    @Test
+    public void toLatLngDegrees_matchesTestVector() {
+        for (int level = 0; level <= 30; level++) {
+            double[] expected = TIMES_SQUARE_CELLS[level].mCenter;
+            long cellId = S2CellIdUtils.getParent(TIMES_SQUARE_S2_ID, level);
+
+            double[] centerPoint = {0.0, 0.0};
+            S2CellIdUtils.toLatLngDegrees(cellId, centerPoint);
+
+            assertThat(approxEquals(centerPoint[0], expected[0])).isTrue();
+            assertThat(approxEquals(centerPoint[1], expected[1])).isTrue();
+        }
+    }
+
+    private static boolean approxEquals(double a, double b) {
+        return Math.abs(a - b) <= 1e-14;
+    }
+
+    @Test
+    public void containsLatLngDegrees_eachCellContainsItsCenter_works() {
+        for (int level = 0; level <= 30; level++) {
+            long cellId = TIMES_SQUARE_CELLS[level].toCellId();
+            double[] center = TIMES_SQUARE_CELLS[level].mCenter;
+
+            boolean isContained = S2CellIdUtils.containsLatLngDegrees(cellId, center[0], center[1]);
+
+            assertThat(isContained).isTrue();
+        }
+    }
+
+    @Test
+    public void containsLatLngDegrees_testWithOutsidePoint() {
+        for (int level = 0; level <= 30; level++) {
+            long cellId = TIMES_SQUARE_CELLS[level].toCellId();
+
+            assertThat(S2CellIdUtils.containsLatLngDegrees(cellId, EIFFEL_TOWER_LATLNG[0],
+                  EIFFEL_TOWER_LATLNG[1])).isFalse();
+        }
+    }
+
+    // A tuple with a S2 cell id, and a S2LatLng representing its center.
+    private static class CellAndCenter {
+        public String mToken;
+        public double[] mCenter;
+
+        CellAndCenter(String token, double latDegrees, double lngDegrees) {
+            this.mToken = token;
+            this.mCenter = new double[] {latDegrees, lngDegrees};
+        }
+
+        // Converts from hex representation to long format.
+        long toCellId() {
+            long value = 0;
+            for (int pos = 0; pos < mToken.length(); pos++) {
+                int digitValue = Character.digit(mToken.charAt(pos), 16);
+                if (digitValue == -1) {
+                    return -1;
+                }
+                value = value * 16 + digitValue;
+            }
+            value = value << (4 * (16 - mToken.length()));  // remove implicit zeros
+            return value;
+        }
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java
index 20ac078..0304a74 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java
@@ -79,12 +79,14 @@
     @Mock private SharedLibrariesImpl mSharedLibraries;
     @Mock private Context mContext;
     @Mock private Computer mComputer;
+    @Mock private PackageInstallerService mPackageInstallerService;
     private InstallDependencyHelper mInstallDependencyHelper;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mInstallDependencyHelper = new InstallDependencyHelper(mContext, mSharedLibraries);
+        mInstallDependencyHelper = new InstallDependencyHelper(mContext, mSharedLibraries,
+                mPackageInstallerService);
     }
 
     @Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 0a6edf1..b53dbc8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -218,6 +218,8 @@
         val handler = TestHandler(null)
         val defaultAppProvider: DefaultAppProvider = mock()
         val backgroundHandler = TestHandler(null)
+        val packageInstallerService: PackageInstallerService = mock()
+        val installDependencyHelper: InstallDependencyHelper = mock()
         val updateOwnershipHelper: UpdateOwnershipHelper = mock()
     }
 
@@ -306,6 +308,7 @@
         whenever(mocks.injector.handler) { mocks.handler }
         whenever(mocks.injector.defaultAppProvider) { mocks.defaultAppProvider }
         whenever(mocks.injector.backgroundHandler) { mocks.backgroundHandler }
+        whenever(mocks.injector.packageInstallerService) { mocks.packageInstallerService }
         whenever(mocks.injector.updateOwnershipHelper) { mocks.updateOwnershipHelper }
         whenever(mocks.injector.getSystemService(AppOpsManager::class.java)) { mocks.appOpsManager }
         wheneverStatic { SystemConfig.getInstance() }.thenReturn(mocks.systemConfig)
@@ -332,6 +335,8 @@
             DEVICE_PROVISIONING_PACKAGE_NAME
         }
         whenever(mocks.apexManager.activeApexInfos).thenReturn(DEFAULT_ACTIVE_APEX_INFO_LIST)
+        whenever(mocks.packageInstallerService.installDependencyHelper).thenReturn(
+            mocks.installDependencyHelper)
         whenever(mocks.settings.packagesLocked).thenReturn(mSettingsMap)
         whenever(mocks.settings.internalVersion).thenReturn(DEFAULT_VERSION_INFO)
         whenever(mocks.settings.keySetManagerService).thenReturn(mocks.keySetManagerService)
diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
index e631cb6..313c01d 100644
--- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -18,7 +18,6 @@
 
 
 import static com.android.server.power.hint.HintManagerService.CLEAN_UP_UID_DELAY_MILLIS;
-import static com.android.server.power.hint.HintManagerService.DEFAULT_HEADROOM_PID;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -53,7 +52,9 @@
 import android.hardware.power.ChannelConfig;
 import android.hardware.power.ChannelMessage;
 import android.hardware.power.CpuHeadroomParams;
+import android.hardware.power.CpuHeadroomResult;
 import android.hardware.power.GpuHeadroomParams;
+import android.hardware.power.GpuHeadroomResult;
 import android.hardware.power.IPower;
 import android.hardware.power.SessionConfig;
 import android.hardware.power.SessionTag;
@@ -1251,67 +1252,98 @@
         CpuHeadroomParams halParams1 = new CpuHeadroomParams();
         halParams1.calculationType = CpuHeadroomParams.CalculationType.MIN;
         halParams1.selectionType = CpuHeadroomParams.SelectionType.ALL;
-        halParams1.pid = Process.myPid();
+        halParams1.tids = new int[]{Process.myPid()};
 
         CpuHeadroomParamsInternal params2 = new CpuHeadroomParamsInternal();
         params2.usesDeviceHeadroom = true;
-        params2.calculationType = CpuHeadroomParams.CalculationType.AVERAGE;
+        params2.calculationType = CpuHeadroomParams.CalculationType.MIN;
         params2.selectionType = CpuHeadroomParams.SelectionType.PER_CORE;
         CpuHeadroomParams halParams2 = new CpuHeadroomParams();
-        halParams2.calculationType = CpuHeadroomParams.CalculationType.AVERAGE;
+        halParams2.calculationType = CpuHeadroomParams.CalculationType.MIN;
         halParams2.selectionType = CpuHeadroomParams.SelectionType.PER_CORE;
-        halParams2.pid = DEFAULT_HEADROOM_PID;
+        halParams2.tids = new int[]{};
 
-        float[] headroom1 = new float[] {0.1f};
-        when(mIPowerMock.getCpuHeadroom(eq(halParams1))).thenReturn(headroom1);
-        float[] headroom2 = new float[] {0.1f, 0.5f};
-        when(mIPowerMock.getCpuHeadroom(eq(halParams2))).thenReturn(headroom2);
+        CpuHeadroomParamsInternal params3 = new CpuHeadroomParamsInternal();
+        params3.calculationType = CpuHeadroomParams.CalculationType.AVERAGE;
+        params3.selectionType = CpuHeadroomParams.SelectionType.ALL;
+        CpuHeadroomParams halParams3 = new CpuHeadroomParams();
+        halParams3.calculationType = CpuHeadroomParams.CalculationType.AVERAGE;
+        halParams3.selectionType = CpuHeadroomParams.SelectionType.ALL;
+        halParams3.tids = new int[]{Process.myPid()};
+
+        // this params should not be cached as the window is not default
+        CpuHeadroomParamsInternal params4 = new CpuHeadroomParamsInternal();
+        params4.calculationWindowMillis = 123;
+        CpuHeadroomParams halParams4 = new CpuHeadroomParams();
+        halParams4.calculationType = CpuHeadroomParams.CalculationType.MIN;
+        halParams4.selectionType = CpuHeadroomParams.SelectionType.ALL;
+        halParams4.calculationWindowMillis = 123;
+        halParams4.tids = new int[]{Process.myPid()};
+
+        float headroom1 = 0.1f;
+        CpuHeadroomResult halRet1 = CpuHeadroomResult.globalHeadroom(headroom1);
+        when(mIPowerMock.getCpuHeadroom(eq(halParams1))).thenReturn(halRet1);
+        float[] headroom2 = new float[] {0.2f, 0.2f};
+        CpuHeadroomResult halRet2 = CpuHeadroomResult.perCoreHeadroom(headroom2);
+        when(mIPowerMock.getCpuHeadroom(eq(halParams2))).thenReturn(halRet2);
+        float headroom3 = 0.3f;
+        CpuHeadroomResult halRet3 = CpuHeadroomResult.globalHeadroom(headroom3);
+        when(mIPowerMock.getCpuHeadroom(eq(halParams3))).thenReturn(halRet3);
+        float headroom4 = 0.4f;
+        CpuHeadroomResult halRet4 = CpuHeadroomResult.globalHeadroom(headroom4);
+        when(mIPowerMock.getCpuHeadroom(eq(halParams4))).thenReturn(halRet4);
 
         HintManagerService service = createService();
         clearInvocations(mIPowerMock);
 
         service.getBinderServiceInstance().getCpuHeadroomMinIntervalMillis();
         verify(mIPowerMock, times(0)).getCpuHeadroomMinIntervalMillis();
-        service.getBinderServiceInstance().getCpuHeadroom(params1);
+        assertEquals(halRet1, service.getBinderServiceInstance().getCpuHeadroom(params1));
         verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams1));
-        service.getBinderServiceInstance().getCpuHeadroom(params2);
+        assertEquals(halRet2, service.getBinderServiceInstance().getCpuHeadroom(params2));
         verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams2));
+        assertEquals(halRet3, service.getBinderServiceInstance().getCpuHeadroom(params3));
+        verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams3));
+        assertEquals(halRet4, service.getBinderServiceInstance().getCpuHeadroom(params4));
+        verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams4));
 
         // verify cache is working
         clearInvocations(mIPowerMock);
-        assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1),
-                0.01f);
-        assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2),
-                0.01f);
-        verify(mIPowerMock, times(0)).getCpuHeadroom(any());
+        assertEquals(halRet1, service.getBinderServiceInstance().getCpuHeadroom(params1));
+        assertEquals(halRet2, service.getBinderServiceInstance().getCpuHeadroom(params2));
+        assertEquals(halRet3, service.getBinderServiceInstance().getCpuHeadroom(params3));
+        assertEquals(halRet4, service.getBinderServiceInstance().getCpuHeadroom(params4));
+        verify(mIPowerMock, times(1)).getCpuHeadroom(any());
+        verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams1));
+        verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams2));
+        verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams3));
+        verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams4));
 
         // after 1 more second it should be served with cache still
         Thread.sleep(1000);
         clearInvocations(mIPowerMock);
-        assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1),
-                0.01f);
-        assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2),
-                0.01f);
-        verify(mIPowerMock, times(0)).getCpuHeadroom(any());
-
-        // after 1.5 more second it should be served with cache still as timer reset
-        Thread.sleep(1500);
-        clearInvocations(mIPowerMock);
-        assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1),
-                0.01f);
-        assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2),
-                0.01f);
-        verify(mIPowerMock, times(0)).getCpuHeadroom(any());
+        assertEquals(halRet1, service.getBinderServiceInstance().getCpuHeadroom(params1));
+        assertEquals(halRet2, service.getBinderServiceInstance().getCpuHeadroom(params2));
+        assertEquals(halRet3, service.getBinderServiceInstance().getCpuHeadroom(params3));
+        assertEquals(halRet4, service.getBinderServiceInstance().getCpuHeadroom(params4));
+        verify(mIPowerMock, times(1)).getCpuHeadroom(any());
+        verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams1));
+        verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams2));
+        verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams3));
+        verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams4));
 
         // after 2+ seconds it should be served from HAL as it exceeds 2000 millis interval
-        Thread.sleep(2100);
+        Thread.sleep(1100);
         clearInvocations(mIPowerMock);
-        assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1),
-                0.01f);
-        assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2),
-                0.01f);
+        assertEquals(halRet1, service.getBinderServiceInstance().getCpuHeadroom(params1));
+        assertEquals(halRet2, service.getBinderServiceInstance().getCpuHeadroom(params2));
+        assertEquals(halRet3, service.getBinderServiceInstance().getCpuHeadroom(params3));
+        assertEquals(halRet4, service.getBinderServiceInstance().getCpuHeadroom(params4));
+        verify(mIPowerMock, times(4)).getCpuHeadroom(any());
         verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams1));
         verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams2));
+        verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams3));
+        verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams4));
     }
 
     @Test
@@ -1322,59 +1354,52 @@
         halParams1.calculationType = GpuHeadroomParams.CalculationType.MIN;
 
         GpuHeadroomParamsInternal params2 = new GpuHeadroomParamsInternal();
+        params2.calculationType = GpuHeadroomParams.CalculationType.AVERAGE;
+        params2.calculationWindowMillis = 123;
         GpuHeadroomParams halParams2 = new GpuHeadroomParams();
-        params2.calculationType =
-                halParams2.calculationType = GpuHeadroomParams.CalculationType.AVERAGE;
+        halParams2.calculationType = GpuHeadroomParams.CalculationType.AVERAGE;
+        halParams2.calculationWindowMillis = 123;
 
         float headroom1 = 0.1f;
-        when(mIPowerMock.getGpuHeadroom(eq(halParams1))).thenReturn(headroom1);
+        GpuHeadroomResult halRet1 = GpuHeadroomResult.globalHeadroom(headroom1);
+        when(mIPowerMock.getGpuHeadroom(eq(halParams1))).thenReturn(halRet1);
         float headroom2 = 0.2f;
-        when(mIPowerMock.getGpuHeadroom(eq(halParams2))).thenReturn(headroom2);
+        GpuHeadroomResult halRet2 = GpuHeadroomResult.globalHeadroom(headroom2);
+        when(mIPowerMock.getGpuHeadroom(eq(halParams2))).thenReturn(halRet2);
         HintManagerService service = createService();
         clearInvocations(mIPowerMock);
 
         service.getBinderServiceInstance().getGpuHeadroomMinIntervalMillis();
         verify(mIPowerMock, times(0)).getGpuHeadroomMinIntervalMillis();
-        assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1),
-                0.01f);
-        assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2),
-                0.01f);
+        assertEquals(halRet1, service.getBinderServiceInstance().getGpuHeadroom(params1));
+        assertEquals(halRet2, service.getBinderServiceInstance().getGpuHeadroom(params2));
+        verify(mIPowerMock, times(2)).getGpuHeadroom(any());
         verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams1));
         verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2));
 
         // verify cache is working
         clearInvocations(mIPowerMock);
-        assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1),
-                0.01f);
-        assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2),
-                0.01f);
-        verify(mIPowerMock, times(0)).getGpuHeadroom(any());
+        assertEquals(halRet1, service.getBinderServiceInstance().getGpuHeadroom(params1));
+        assertEquals(halRet2, service.getBinderServiceInstance().getGpuHeadroom(params2));
+        verify(mIPowerMock, times(1)).getGpuHeadroom(any());
+        verify(mIPowerMock, times(0)).getGpuHeadroom(eq(halParams1));
+        verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2));
 
         // after 1 more second it should be served with cache still
         Thread.sleep(1000);
         clearInvocations(mIPowerMock);
-        assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1),
-                0.01f);
-        assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2),
-                0.01f);
-        verify(mIPowerMock, times(0)).getGpuHeadroom(any());
-
-        // after 1.5 more second it should be served with cache still as timer reset
-        Thread.sleep(1500);
-        clearInvocations(mIPowerMock);
-        assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1),
-                0.01f);
-        assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2),
-                0.01f);
-        verify(mIPowerMock, times(0)).getGpuHeadroom(any());
+        assertEquals(halRet1, service.getBinderServiceInstance().getGpuHeadroom(params1));
+        assertEquals(halRet2, service.getBinderServiceInstance().getGpuHeadroom(params2));
+        verify(mIPowerMock, times(1)).getGpuHeadroom(any());
+        verify(mIPowerMock, times(0)).getGpuHeadroom(eq(halParams1));
+        verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2));
 
         // after 2+ seconds it should be served from HAL as it exceeds 2000 millis interval
-        Thread.sleep(2100);
+        Thread.sleep(1100);
         clearInvocations(mIPowerMock);
-        assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1),
-                0.01f);
-        assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2),
-                0.01f);
+        assertEquals(halRet1, service.getBinderServiceInstance().getGpuHeadroom(params1));
+        assertEquals(halRet2, service.getBinderServiceInstance().getGpuHeadroom(params2));
+        verify(mIPowerMock, times(2)).getGpuHeadroom(any());
         verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams1));
         verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2));
     }
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java
index c0be865..4b91d84 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java
@@ -79,8 +79,6 @@
         // 100,000,00 uC / 1000 (micro-/milli-) / 360 (seconds/hour) = 27.777778 mAh
         assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))
                 .isWithin(PRECISION).of(27.777778);
-        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
     }
 
     @Test
@@ -140,8 +138,6 @@
         // (seconds/hour) = 27.777778 mAh
         assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))
                 .isWithin(PRECISION).of(83.33333);
-        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
     }
 
     @Test
@@ -163,8 +159,6 @@
                 .isEqualTo(90 * MINUTE_IN_MS);
         assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))
                 .isWithin(PRECISION).of(15.0);
-        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
     }
 
     @Test
@@ -195,7 +189,5 @@
                 .isEqualTo(120 * MINUTE_IN_MS);
         assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))
                 .isWithin(PRECISION).of(35.0);
-        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
     }
 }
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsAtomTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsAtomTest.java
index 5d50e6c..9da89fc 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsAtomTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsAtomTest.java
@@ -311,10 +311,6 @@
                 bus.getAggregateBatteryConsumer(AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE),
                 proto.deviceBatteryConsumer);
 
-        for (int i = 0; i < BatteryConsumer.POWER_COMPONENT_COUNT; i++) {
-            assertPowerComponentModel(i, abc.getPowerModel(i), proto);
-        }
-
         // Now for the UidBatteryConsumers.
         final List<android.os.UidBatteryConsumer> uidConsumers = bus.getUidBatteryConsumers();
         uidConsumers.sort((a, b) -> a.getUid() - b.getUid());
@@ -450,34 +446,6 @@
         }
     }
 
-    /**
-     * Validates the PowerComponentModel object that matches powerComponent.
-     */
-    private void assertPowerComponentModel(int powerComponent,
-            @BatteryConsumer.PowerModel int powerModel, BatteryUsageStatsAtomsProto proto) {
-        boolean found = false;
-        for (BatteryUsageStatsAtomsProto.PowerComponentModel powerComponentModel :
-                proto.componentModels) {
-            if (powerComponentModel.component == powerComponent) {
-                if (found) {
-                    fail("Power component " + BatteryConsumer.powerComponentIdToString(
-                            powerComponent) + " found multiple times in the proto");
-                }
-                found = true;
-                final int expectedPowerModel = BatteryConsumer.powerModelToProtoEnum(powerModel);
-                assertEquals(expectedPowerModel, powerComponentModel.powerModel);
-            }
-        }
-        if (!found) {
-            final int model = BatteryConsumer.powerModelToProtoEnum(powerModel);
-            assertEquals(
-                    "Power component " + BatteryConsumer.powerComponentIdToString(powerComponent)
-                            + " was not found in the proto but has a defined power model.",
-                    BatteryUsageStatsAtomsProto.PowerComponentModel.UNDEFINED,
-                    model);
-        }
-    }
-
     /** Converts charge from milliamp hours (mAh) to decicoulombs (dC). */
     private long convertMahToDc(double powerMah) {
         return (long) (powerMah * 36 + 0.5);
@@ -486,7 +454,6 @@
     private BatteryUsageStats buildBatteryUsageStats() {
         final BatteryUsageStats.Builder builder =
                 new BatteryUsageStats.Builder(new String[]{"CustomConsumer1", "CustomConsumer2"},
-                        /* includePowerModels */ true,
                         /* includeProcessStats */ true,
                         /* includeScreenStateData */ false,
                         /* includePowerStateData */ false,
@@ -524,13 +491,13 @@
         final BatteryConsumer.Key keyCached = uidBuilder.getKey(BatteryConsumer.POWER_COMPONENT_CPU,
                 BatteryConsumer.PROCESS_STATE_CACHED);
 
-        uidBuilder.addConsumedPower(keyFg, 9100, BatteryConsumer.POWER_MODEL_POWER_PROFILE)
+        uidBuilder.addConsumedPower(keyFg, 9100)
                 .addUsageDurationMillis(keyFg, 8100)
-                .addConsumedPower(keyBg, 9200, BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION)
+                .addConsumedPower(keyBg, (double) 9200)
                 .addUsageDurationMillis(keyBg, 8200)
-                .addConsumedPower(keyFgs, 9300, BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION)
+                .addConsumedPower(keyFgs, (double) 9300)
                 .addUsageDurationMillis(keyFgs, 8300)
-                .addConsumedPower(keyCached, 9400, BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION)
+                .addConsumedPower(keyCached, (double) 9400)
                 .addUsageDurationMillis(keyCached, 8400);
 
         final BatteryConsumer.Key keyCustomFg = uidBuilder.getKey(
@@ -539,10 +506,8 @@
         final BatteryConsumer.Key keyCustomBg = uidBuilder.getKey(
                 BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID,
                 BatteryConsumer.PROCESS_STATE_BACKGROUND);
-        uidBuilder.addConsumedPower(
-                keyCustomFg, 100, BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
-        uidBuilder.addConsumedPower(
-                keyCustomBg, 350, BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
+        uidBuilder.addConsumedPower(keyCustomFg, 100);
+        uidBuilder.addConsumedPower(keyCustomBg, 350);
 
         builder.getOrCreateUidBatteryConsumerBuilder(UID_1)
                 .setPackageWithHighestDrain("myPackage1")
@@ -557,14 +522,11 @@
         builder.getAggregateBatteryConsumerBuilder(AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
                 .addConsumedPower(30000)
                 .addConsumedPower(
-                        BatteryConsumer.POWER_COMPONENT_CPU, 20100,
-                        BatteryConsumer.POWER_MODEL_POWER_PROFILE)
+                        BatteryConsumer.POWER_COMPONENT_CPU, 20100)
                 .addConsumedPower(
-                        BatteryConsumer.POWER_COMPONENT_AUDIO, 0,
-                        BatteryConsumer.POWER_MODEL_POWER_PROFILE) // Empty
+                        BatteryConsumer.POWER_COMPONENT_AUDIO, 0) // Empty
                 .addConsumedPower(
-                        BatteryConsumer.POWER_COMPONENT_CAMERA, 20150,
-                        BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION)
+                        BatteryConsumer.POWER_COMPONENT_CAMERA, 20150)
                 .addConsumedPower(
                         BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 20200)
                 .addUsageDurationMillis(
@@ -576,8 +538,7 @@
         builder.getAggregateBatteryConsumerBuilder(
                         BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS)
                 .addConsumedPower(
-                        BatteryConsumer.POWER_COMPONENT_CPU, 10100,
-                        BatteryConsumer.POWER_MODEL_POWER_PROFILE)
+                        BatteryConsumer.POWER_COMPONENT_CPU, 10100)
                 .addConsumedPower(
                         BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10200);
 
@@ -587,7 +548,7 @@
     @Test
     public void testLargeAtomTruncated() throws Exception {
         final BatteryUsageStats.Builder builder =
-                new BatteryUsageStats.Builder(new String[0], true, false, false, false, 0);
+                new BatteryUsageStats.Builder(new String[0], false, false, false, 0);
         // If not truncated, this BatteryUsageStats object would generate a proto buffer
         // significantly larger than 50 Kb
         for (int i = 0; i < 3000; i++) {
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
index 383616e..a3c7ece 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
@@ -423,8 +423,6 @@
             mBatteryUsageStats = null;
         }
         final String[] customPowerComponentNames = mBatteryStats.getCustomEnergyConsumerNames();
-        final boolean includePowerModels = (query.getFlags()
-                & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
         final boolean includeProcessStateData = (query.getFlags()
                 & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA) != 0;
         final boolean includeScreenStateData = (query.getFlags()
@@ -433,7 +431,7 @@
                 & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_STATE) != 0;
         final double minConsumedPowerThreshold = query.getMinConsumedPowerThreshold();
         BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
-                customPowerComponentNames, includePowerModels, includeProcessStateData,
+                customPowerComponentNames, includeProcessStateData,
                 includeScreenStateData, includePowerStateData, minConsumedPowerThreshold);
         SparseArray<? extends BatteryStats.Uid> uidStats = mBatteryStats.getUidStats();
         for (int i = 0; i < uidStats.size(); i++) {
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java
index 9771da5..dd50431 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java
@@ -17,8 +17,6 @@
 package com.android.server.power.stats;
 
 import static android.os.BatteryConsumer.POWER_COMPONENT_ANY;
-import static android.os.BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION;
-import static android.os.BatteryConsumer.POWER_MODEL_UNDEFINED;
 import static android.os.BatteryConsumer.PROCESS_STATE_BACKGROUND;
 import static android.os.BatteryConsumer.PROCESS_STATE_CACHED;
 import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND;
@@ -237,7 +235,7 @@
         final BatteryUsageStats stats1 = buildBatteryUsageStats1(false).build();
         final BatteryUsageStats stats2 = buildBatteryUsageStats2(new String[]{"FOO"}, true).build();
         final BatteryUsageStats sum =
-                new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true, true, true, 0)
+                new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true, true, 0)
                         .add(stats1)
                         .add(stats2)
                         .build();
@@ -248,15 +246,13 @@
         for (UidBatteryConsumer uidBatteryConsumer : uidBatteryConsumers) {
             if (uidBatteryConsumer.getUid() == APP_UID1) {
                 assertUidBatteryConsumer(uidBatteryConsumer, 1200 + 924, null,
-                        5321, 6900, 532, 423, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 400 + 345,
-                        POWER_MODEL_UNDEFINED,
+                        5321, 6900, 532, 423, 400 + 345,
                         500 + 456, 1167, 1478,
                         true, 3554, 4732, 3998, 444, 3554, 15542, 3776, 17762, 3998, 19982,
                         444, 1110);
             } else if (uidBatteryConsumer.getUid() == APP_UID2) {
                 assertUidBatteryConsumer(uidBatteryConsumer, 1332, "bar",
-                        1111, 2220, 2, 333, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 444,
-                        BatteryConsumer.POWER_MODEL_POWER_PROFILE,
+                        1111, 2220, 2, 333, 444,
                         555, 666, 777,
                         true, 1777, 2443, 1999, 321, 1777, 7771, 1888, 8881, 1999, 9991,
                         321, 654);
@@ -280,7 +276,7 @@
     @Test
     public void testAdd_customComponentMismatch() throws Exception {
         final BatteryUsageStats.Builder builder =
-                new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true, true, true, 0);
+                new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true, true, 0);
         final BatteryUsageStats stats = buildBatteryUsageStats2(new String[]{"BAR"}, false).build();
 
         assertThrows(IllegalArgumentException.class, () -> builder.add(stats));
@@ -291,7 +287,7 @@
     @Test
     public void testAdd_processStateDataMismatch() throws Exception {
         final BatteryUsageStats.Builder builder =
-                new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true, true, true, 0);
+                new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true, true, 0);
         final BatteryUsageStats stats = buildBatteryUsageStats2(new String[]{"FOO"}, false).build();
 
         assertThrows(IllegalArgumentException.class, () -> builder.add(stats));
@@ -328,7 +324,7 @@
         final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks);
 
         final BatteryUsageStats.Builder builder =
-                new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true,
+                new BatteryUsageStats.Builder(new String[]{"FOO"}, true,
                         includeScreenState, includePowerState, 0)
                         .setBatteryCapacity(4000)
                         .setDischargePercentage(20)
@@ -339,8 +335,8 @@
 
         addUidBatteryConsumer(builder, batteryStats, APP_UID1, "foo",
                 1000, 1500, 500,
-                300, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 400,
-                BatteryConsumer.POWER_MODEL_POWER_PROFILE, 500, 600, 800,
+                300, 400,
+                500, 600, 800,
                 1777, 7771, 1888, 8881, 1999, 9991, 123, 456);
 
         addAggregateBatteryConsumer(builder,
@@ -373,7 +369,7 @@
         final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks);
 
         final BatteryUsageStats.Builder builder =
-                new BatteryUsageStats.Builder(customPowerComponentNames, true,
+                new BatteryUsageStats.Builder(customPowerComponentNames,
                         includeProcessStateData, true, true, 0);
         builder.setDischargePercentage(30)
                 .setDischargedPowerRange(1234, 2345)
@@ -382,14 +378,14 @@
 
         addUidBatteryConsumer(builder, batteryStats, APP_UID1, null,
                 4321, 5400, 32,
-                123, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 345, POWER_MODEL_ENERGY_CONSUMPTION,
+                123, 345,
                 456, 567, 678,
                 1777, 7771, 1888, 8881, 1999, 9991, 321, 654);
 
         addUidBatteryConsumer(builder, batteryStats, APP_UID2, "bar",
                 1111, 2220, 2,
-                333, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 444,
-                BatteryConsumer.POWER_MODEL_POWER_PROFILE, 555, 666, 777,
+                333, 444,
+                555, 666, 777,
                 1777, 7771, 1888, 8881, 1999, 9991, 321, 654);
 
         addAggregateBatteryConsumer(builder,
@@ -409,7 +405,7 @@
             MockBatteryStatsImpl batteryStats, int uid, String packageWithHighestDrain,
             int timeInProcessStateForeground, int timeInProcessStateBackground,
             int timeInProcessStateForegroundService, double screenPower,
-            int screenPowerModel, double cpuPower, int cpuPowerModel, double customComponentPower,
+            double cpuPower, double customComponentPower,
             int cpuDuration, int customComponentDuration, double cpuPowerForeground,
             int cpuDurationForeground, double cpuPowerBackground, int cpuDurationBackground,
             double cpuPowerFgs, int cpuDurationFgs, double cpuPowerCached, long cpuDurationCached) {
@@ -423,9 +419,9 @@
                 .setTimeInProcessStateMs(PROCESS_STATE_FOREGROUND_SERVICE,
                         timeInProcessStateForegroundService)
                 .addConsumedPower(
-                        BatteryConsumer.POWER_COMPONENT_SCREEN, screenPower, screenPowerModel)
+                        BatteryConsumer.POWER_COMPONENT_SCREEN, screenPower)
                 .addConsumedPower(
-                        BatteryConsumer.POWER_COMPONENT_CPU, cpuPower, cpuPowerModel)
+                        BatteryConsumer.POWER_COMPONENT_CPU, cpuPower)
                 .addConsumedPower(
                         BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, customComponentPower)
                 .addUsageDurationMillis(
@@ -460,21 +456,15 @@
                     : uidBuilder.getKey(
                             BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID,
                             BatteryConsumer.PROCESS_STATE_BACKGROUND);
-            uidBuilder
-                    .addConsumedPower(cpuFgKey, cpuPowerForeground,
-                            BatteryConsumer.POWER_MODEL_POWER_PROFILE)
+            uidBuilder.addConsumedPower(cpuFgKey, cpuPowerForeground)
                     .addUsageDurationMillis(cpuFgKey, cpuDurationForeground)
-                    .addConsumedPower(cpuBgKey, cpuPowerBackground,
-                            BatteryConsumer.POWER_MODEL_POWER_PROFILE)
+                    .addConsumedPower(cpuBgKey, cpuPowerBackground)
                     .addUsageDurationMillis(cpuBgKey, cpuDurationBackground)
-                    .addConsumedPower(cpuFgsKey, cpuPowerFgs,
-                            BatteryConsumer.POWER_MODEL_POWER_PROFILE)
+                    .addConsumedPower(cpuFgsKey, cpuPowerFgs)
                     .addUsageDurationMillis(cpuFgsKey, cpuDurationFgs)
-                    .addConsumedPower(cachedKey, cpuPowerCached,
-                            BatteryConsumer.POWER_MODEL_POWER_PROFILE)
+                    .addConsumedPower(cachedKey, cpuPowerCached)
                     .addUsageDurationMillis(cachedKey, cpuDurationCached)
-                    .addConsumedPower(customBgKey, customComponentPower,
-                            BatteryConsumer.POWER_MODEL_UNDEFINED)
+                    .addConsumedPower(customBgKey, customComponentPower)
                     .addUsageDurationMillis(customBgKey, customComponentDuration);
         }
     }
@@ -518,18 +508,13 @@
                     BatteryConsumer.PROCESS_STATE_UNSPECIFIED,
                     BatteryConsumer.SCREEN_STATE_OTHER,
                     BatteryConsumer.POWER_STATE_OTHER);
-            aggBuilder
-                    .addConsumedPower(cpuBatScrOn, cpuPowerBatScrOn,
-                            BatteryConsumer.POWER_MODEL_POWER_PROFILE)
+            aggBuilder.addConsumedPower(cpuBatScrOn, cpuPowerBatScrOn)
                     .addUsageDurationMillis(cpuBatScrOn, cpuDurationBatScrOn)
-                    .addConsumedPower(cpuBatScrOff, cpuPowerBatScrOff,
-                            BatteryConsumer.POWER_MODEL_POWER_PROFILE)
+                    .addConsumedPower(cpuBatScrOff, cpuPowerBatScrOff)
                     .addUsageDurationMillis(cpuBatScrOff, cpuDurationBatScrOff)
-                    .addConsumedPower(cpuChgScrOn, cpuPowerChgScrOn,
-                            BatteryConsumer.POWER_MODEL_POWER_PROFILE)
+                    .addConsumedPower(cpuChgScrOn, cpuPowerChgScrOn)
                     .addUsageDurationMillis(cpuChgScrOn, cpuDurationChgScrOn)
-                    .addConsumedPower(cpuChgScrOff, cpuPowerChgScrOff,
-                            BatteryConsumer.POWER_MODEL_POWER_PROFILE)
+                    .addConsumedPower(cpuChgScrOff, cpuPowerChgScrOff)
                     .addUsageDurationMillis(cpuChgScrOff, cpuDurationChgScrOff);
         }
     }
@@ -544,8 +529,7 @@
         for (UidBatteryConsumer uidBatteryConsumer : uidBatteryConsumers) {
             if (uidBatteryConsumer.getUid() == APP_UID1) {
                 assertUidBatteryConsumer(uidBatteryConsumer, 1200, "foo",
-                        1000, 1500, 500, 300, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 400,
-                        BatteryConsumer.POWER_MODEL_POWER_PROFILE,
+                        1000, 1500, 500, 300, 400,
                         500, 600, 800,
                         true, 1777, 2388, 1999, 123, 1777, 7771, 1888, 8881, 1999, 9991, 123, 456);
             } else {
@@ -596,8 +580,8 @@
     private void assertUidBatteryConsumer(UidBatteryConsumer uidBatteryConsumer,
             double consumedPower, String packageWithHighestDrain, int timeInProcessStateForeground,
             int timeInProcessStateBackground, int timeInProcessStateForegroundService,
-            int screenPower, int screenPowerModel, double cpuPower,
-            int cpuPowerModel, double customComponentPower, int cpuDuration,
+            int screenPower, double cpuPower,
+            double customComponentPower, int cpuDuration,
             int customComponentDuration, boolean processStateDataIncluded,
             double totalPowerForeground, double totalPowerBackground, double totalPowerFgs,
             double totalPowerCached, double cpuPowerForeground, int cpuDurationForeground,
@@ -620,12 +604,8 @@
                 PROCESS_STATE_FOREGROUND_SERVICE)).isEqualTo(timeInProcessStateForegroundService);
         assertThat(uidBatteryConsumer.getConsumedPower(
                 BatteryConsumer.POWER_COMPONENT_SCREEN)).isEqualTo(screenPower);
-        assertThat(uidBatteryConsumer.getPowerModel(
-                BatteryConsumer.POWER_COMPONENT_SCREEN)).isEqualTo(screenPowerModel);
         assertThat(uidBatteryConsumer.getConsumedPower(
                 BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(cpuPower);
-        assertThat(uidBatteryConsumer.getPowerModel(
-                BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(cpuPowerModel);
         assertThat(uidBatteryConsumer.getConsumedPower(
                 BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(customComponentPower);
         assertThat(uidBatteryConsumer.getUsageDurationMillis(
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BluetoothPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BluetoothPowerCalculatorTest.java
index fe6424f..c9cb0df 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BluetoothPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BluetoothPowerCalculatorTest.java
@@ -82,16 +82,16 @@
 
         assertBluetoothPowerAndDuration(
                 mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID),
-                0.06944, 3000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+                0.06944, 3000);
         assertBluetoothPowerAndDuration(
                 mStatsRule.getUidBatteryConsumer(APP_UID),
-                0.19444, 9000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+                0.19444, 9000);
         assertBluetoothPowerAndDuration(
                 mStatsRule.getDeviceBatteryConsumer(),
-                0.26388, 12000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+                0.26388, 12000);
         assertBluetoothPowerAndDuration(
                 mStatsRule.getAppsBatteryConsumer(),
-                0.26388, 12000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+                0.26388, 12000);
     }
 
     @Test
@@ -144,8 +144,6 @@
                 .isEqualTo(6166);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH))
                 .isWithin(PRECISION).of(0.1226666);
-        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_BLUETOOTH))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         final BatteryConsumer.Key foreground = uidConsumer.getKey(
                 BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
@@ -178,16 +176,16 @@
 
         assertBluetoothPowerAndDuration(
                 mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID),
-                0.08216, 3583, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+                0.08216, 3583);
         assertBluetoothPowerAndDuration(
                 mStatsRule.getUidBatteryConsumer(APP_UID),
-                0.18169, 8416, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+                0.18169, 8416);
         assertBluetoothPowerAndDuration(
                 mStatsRule.getDeviceBatteryConsumer(),
-                0.30030, 12000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+                0.30030, 12000);
         assertBluetoothPowerAndDuration(
                 mStatsRule.getAppsBatteryConsumer(),
-                0.26386, 11999, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+                0.26386, 11999);
     }
 
     @Test
@@ -202,16 +200,16 @@
 
         assertBluetoothPowerAndDuration(
                 mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID),
-                0.10378, 3583, BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
+                0.10378, 3583);
         assertBluetoothPowerAndDuration(
                 mStatsRule.getUidBatteryConsumer(APP_UID),
-                0.22950, 8416, BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
+                0.22950, 8416);
         assertBluetoothPowerAndDuration(
                 mStatsRule.getDeviceBatteryConsumer(),
-                0.33333, 12000, BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
+                0.33333, 12000);
         assertBluetoothPowerAndDuration(
                 mStatsRule.getAppsBatteryConsumer(),
-                0.33329, 11999, BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
+                0.33329, 11999);
     }
 
     @Test
@@ -264,8 +262,6 @@
                 .isEqualTo(6166);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH))
                 .isWithin(PRECISION).of(0.8220561);
-        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_BLUETOOTH))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         final BatteryConsumer.Key foreground = uidConsumer.getKey(
                 BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
@@ -299,16 +295,16 @@
 
         assertBluetoothPowerAndDuration(
                 mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID),
-                0.08216, 3583, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+                0.08216, 3583);
         assertBluetoothPowerAndDuration(
                 mStatsRule.getUidBatteryConsumer(APP_UID),
-                0.18169, 8416, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+                0.18169, 8416);
         assertBluetoothPowerAndDuration(
                 mStatsRule.getDeviceBatteryConsumer(),
-                0.26388, 12000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+                0.26388, 12000);
         assertBluetoothPowerAndDuration(
                 mStatsRule.getAppsBatteryConsumer(),
-                0.26386, 11999, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+                0.26386, 11999);
     }
 
     private void setupBluetoothEnergyInfo(long reportedEnergyUc, long consumedEnergyUc) {
@@ -326,14 +322,12 @@
     }
 
     private void assertBluetoothPowerAndDuration(@Nullable BatteryConsumer batteryConsumer,
-            double powerMah, int durationMs, @BatteryConsumer.PowerModel int powerModel) {
+            double powerMah, int durationMs) {
         assertThat(batteryConsumer).isNotNull();
 
         double consumedPower = batteryConsumer.getConsumedPower(
                 BatteryConsumer.POWER_COMPONENT_BLUETOOTH);
         assertThat(consumedPower).isWithin(PRECISION).of(powerMah);
-        assertThat(batteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_BLUETOOTH))
-                .isEqualTo(powerModel);
 
         long usageDurationMillis = batteryConsumer.getUsageDurationMillis(
                 BatteryConsumer.POWER_COMPONENT_BLUETOOTH);
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/CameraPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CameraPowerCalculatorTest.java
index 7225f2d..4cd3857 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/CameraPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CameraPowerCalculatorTest.java
@@ -70,16 +70,12 @@
                 .isEqualTo(1000);
         assertThat(app1Consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
                 .isWithin(PRECISION).of(0.1);
-        assertThat(app1Consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         UidBatteryConsumer app2Consumer = mStatsRule.getUidBatteryConsumer(APP2_UID);
         assertThat(app2Consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA))
                 .isEqualTo(2000);
         assertThat(app2Consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
                 .isWithin(PRECISION).of(0.2);
-        assertThat(app2Consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         final BatteryConsumer deviceBatteryConsumer = mStatsRule.getDeviceBatteryConsumer();
         assertThat(deviceBatteryConsumer
@@ -87,8 +83,6 @@
                 .isEqualTo(3000);
         assertThat(deviceBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
                 .isWithin(PRECISION).of(0.3);
-        assertThat(deviceBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         final BatteryConsumer appsBatteryConsumer = mStatsRule.getAppsBatteryConsumer();
         assertThat(appsBatteryConsumer
@@ -96,8 +90,6 @@
                 .isEqualTo(3000);
         assertThat(appsBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
                 .isWithin(PRECISION).of(0.3);
-        assertThat(appsBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
     }
 
     @Test
@@ -122,16 +114,12 @@
                 .isEqualTo(1000);
         assertThat(app1Consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
                 .isWithin(PRECISION).of(0.2);
-        assertThat(app1Consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         UidBatteryConsumer app2Consumer = mStatsRule.getUidBatteryConsumer(APP2_UID);
         assertThat(app2Consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA))
                 .isEqualTo(2000);
         assertThat(app2Consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
                 .isWithin(PRECISION).of(0.3);
-        assertThat(app2Consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         final BatteryConsumer deviceBatteryConsumer = mStatsRule.getDeviceBatteryConsumer();
         assertThat(deviceBatteryConsumer
@@ -139,8 +127,6 @@
                 .isEqualTo(3000);
         assertThat(deviceBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
                 .isWithin(PRECISION).of(0.5);
-        assertThat(deviceBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         final BatteryConsumer appsBatteryConsumer = mStatsRule.getAppsBatteryConsumer();
         assertThat(appsBatteryConsumer
@@ -148,7 +134,5 @@
                 .isEqualTo(3000);
         assertThat(appsBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
                 .isWithin(PRECISION).of(0.5);
-        assertThat(appsBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
     }
 }
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerCalculatorTest.java
index 4cea728..527db67 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerCalculatorTest.java
@@ -192,8 +192,6 @@
                 .isEqualTo(3333);
         assertThat(uidConsumer1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
                 .isWithin(PRECISION).of(1.031677);
-        assertThat(uidConsumer1.getPowerModel(BatteryConsumer.POWER_COMPONENT_CPU))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
         assertThat(uidConsumer1.getPackageWithHighestDrain()).isEqualTo("bar");
 
         UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
@@ -201,21 +199,15 @@
                 .isEqualTo(7777);
         assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
                 .isWithin(PRECISION).of(2.489544);
-        assertThat(uidConsumer2.getPowerModel(BatteryConsumer.POWER_COMPONENT_CPU))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
         assertThat(uidConsumer2.getPackageWithHighestDrain()).isNull();
 
         final BatteryConsumer deviceBatteryConsumer = mStatsRule.getDeviceBatteryConsumer();
         assertThat(deviceBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
                 .isWithin(PRECISION).of(3.52122);
-        assertThat(deviceBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CPU))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         final BatteryConsumer appsBatteryConsumer = mStatsRule.getAppsBatteryConsumer();
         assertThat(appsBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
                 .isWithin(PRECISION).of(3.52122);
-        assertThat(appsBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CPU))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
     }
 
     @Test
@@ -264,8 +256,6 @@
                 .isEqualTo(3333);
         assertThat(uidConsumer1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
                 .isWithin(PRECISION).of(3.18877);
-        assertThat(uidConsumer1.getPowerModel(BatteryConsumer.POWER_COMPONENT_CPU))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
         assertThat(uidConsumer1.getPackageWithHighestDrain()).isEqualTo("bar");
 
         UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
@@ -273,21 +263,15 @@
                 .isEqualTo(7777);
         assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
                 .isWithin(PRECISION).of(7.44072);
-        assertThat(uidConsumer2.getPowerModel(BatteryConsumer.POWER_COMPONENT_CPU))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
         assertThat(uidConsumer2.getPackageWithHighestDrain()).isNull();
 
         final BatteryConsumer deviceBatteryConsumer = mStatsRule.getDeviceBatteryConsumer();
         assertThat(deviceBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
                 .isWithin(PRECISION).of(10.62949);
-        assertThat(deviceBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CPU))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         final BatteryConsumer appsBatteryConsumer = mStatsRule.getDeviceBatteryConsumer();
         assertThat(appsBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
                 .isWithin(PRECISION).of(10.62949);
-        assertThat(appsBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CPU))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
     }
 
     @Test
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java
index 005ceee..c7fad76 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java
@@ -29,8 +29,6 @@
 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.RavenwoodFlagsValueProvider;
-import android.platform.test.ravenwood.RavenwoodRule;
 import android.provider.DeviceConfig;
 
 import androidx.test.InstrumentationRegistry;
@@ -59,13 +57,8 @@
 @LargeTest
 @android.platform.test.annotations.DisabledOnRavenwood(reason = "Integration test")
 public class CpuPowerStatsCollectorValidationTest {
-    @Rule(order = 0)
-    public final RavenwoodRule mRavenwood = new RavenwoodRule();
-
-    @Rule(order = 1)
-    public final CheckFlagsRule mCheckFlagsRule = RavenwoodRule.isOnRavenwood()
-            ? RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule()
-            : DeviceFlagsValueProvider.createCheckFlagsRule();
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
 
     private static final int WORK_DURATION_MS = 2000;
     private static final String TEST_PKG = "com.android.coretests.apps.bstatstestapp";
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/GnssPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/GnssPowerCalculatorTest.java
index 3b5658c..506bab4 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/GnssPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/GnssPowerCalculatorTest.java
@@ -68,20 +68,14 @@
                 .isEqualTo(1000);
         assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS))
                 .isWithin(PRECISION).of(0.1);
-        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_GNSS))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS))
                 .isWithin(PRECISION).of(0.1);
-        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_GNSS))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
         assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS))
                 .isWithin(PRECISION).of(0.1);
-        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_GNSS))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
     }
 
     @Test
@@ -107,27 +101,19 @@
                 .isEqualTo(1000);
         assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS))
                 .isWithin(PRECISION).of(2.77777);
-        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_GNSS))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         UidBatteryConsumer consumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
         assertThat(consumer2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_GNSS))
                 .isEqualTo(2000);
         assertThat(consumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS))
                 .isWithin(PRECISION).of(5.55555);
-        assertThat(consumer2.getPowerModel(BatteryConsumer.POWER_COMPONENT_GNSS))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS))
                 .isWithin(PRECISION).of(8.333333);
-        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_GNSS))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
         assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS))
                 .isWithin(PRECISION).of(8.333333);
-        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_GNSS))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
     }
 }
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java
index 9b810bc..eba820e 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java
@@ -164,8 +164,6 @@
         // =    4604000 mA-ms or 1.27888 mA-h
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(1.27888);
-        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         //    720 mA * 100 ms  (level 0 TX drain rate * level 0 TX duration)
         // + 1080 mA * 200 ms  (level 1 TX drain rate * level 1 TX duration)
@@ -178,22 +176,16 @@
         BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
         assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(0.94);
-        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         // 3/4 of total packets were sent by APP_UID so 75% of total
         UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(0.705);
-        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         // Rest should go to the other app
         UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
         assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(0.235);
-        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
     }
 
     @Test
@@ -321,8 +313,6 @@
         // =    5177753 mA-ms or 1.43826 mA-h total consumption
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(1.43826);
-        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         //    720 mA * 100 ms  (level 0 TX drain rate * level 0 TX duration)
         // + 1080 mA * 200 ms  (level 1 TX drain rate * level 1 TX duration)
@@ -335,22 +325,16 @@
         BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
         assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(1.09938);
-        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         // 3/4 of total packets were sent by APP_UID so 75% of total
         UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(0.82453);
-        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         // Rest should go to the other app
         UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
         assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(0.27484);
-        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
     }
 
     @Test
@@ -441,8 +425,6 @@
         // =    4604000 mA-ms or 1.27888 mA-h
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(1.27888);
-        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         //    720 mA * 100 ms  (level 0 TX drain rate * level 0 TX duration)
         // + 1080 mA * 200 ms  (level 1 TX drain rate * level 1 TX duration)
@@ -455,22 +437,16 @@
         BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
         assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(0.94);
-        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         // 3/4 of total packets were sent by APP_UID so 75% of total
         UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(0.705);
-        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         // Rest should go to the other app
         UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
         assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(0.235);
-        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
     }
 
     @Test
@@ -648,24 +624,16 @@
         // 200ms phone on duration / 2000 total duration *  2.77778 mAh = 0.27777
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(2.5);
-        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE))
                 .isWithin(PRECISION).of(0.27778);
-        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_PHONE))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
         assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(1.38541);
-        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(1.38541);
-        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
     }
 
     @Test
@@ -782,12 +750,8 @@
         // 1000ms phone on duration / 10000 total duration *  2.77778 mAh = 0.27777
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(2.5);
-        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE))
                 .isWithin(PRECISION).of(0.27778);
-        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_PHONE))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         // CDMA2000 [Tx0, Tx1, Tx2, Tx3, Tx4, Rx] drain * duration
         //   [720, 1080, 1440, 1800, 2160, 1440] mA . [10, 11, 12, 13, 14, 15] ms = 111600 mA-ms
@@ -817,8 +781,6 @@
         BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
         assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(1.91094);
-        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         // 240 ms Rx Time, 1110 ms Tx Time, 1350 ms active time
         // 150 App 1 Rx Packets, 10 App 1 Tx packets
@@ -841,15 +803,11 @@
         UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(1.27574);
-        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         // Rest should go to the other app
         UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
         assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(0.63520);
-        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
     }
 
     @Test
@@ -936,12 +894,8 @@
         // 1000ms phone on duration / 10000 total duration *  2.77778 mAh = 0.27777
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(2.5);
-        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE))
                 .isWithin(PRECISION).of(0.27778);
-        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_PHONE))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
         // Estimated Rx/Tx modem consumption = 0.94 mAh
@@ -949,14 +903,10 @@
         // 2.5 * 0.94 / 1.27888 = 1.83754 mAh
         assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(1.83754);
-        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(1.83754);
-        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
     }
 
     @Test
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/ScreenPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/ScreenPowerCalculatorTest.java
index 2da98e8..7f20035 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/ScreenPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/ScreenPowerCalculatorTest.java
@@ -104,8 +104,6 @@
         // Uid1 charge = 200000000 + 5 / 45 * 300000000 mAs = 64.81 mAh
         assertThat(uid1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(64.81481);
-        assertThat(uid1.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         UidBatteryConsumer uid2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
         assertThat(uid2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
@@ -116,8 +114,6 @@
         // Uid2 charge = 40 / 45 * 300000000 + 100000000 mAs = 101.85 mAh
         assertThat(uid2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(101.85185);
-        assertThat(uid2.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
         assertThat(deviceConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
@@ -126,8 +122,6 @@
         // 600000000 uAs * (1 mA / 1000 uA) * (1 h / 3600 s)  = 166.66666 mAh
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(166.66666);
-        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
         assertThat(appsConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
@@ -135,11 +129,8 @@
 
         assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(166.66666);
-        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
     }
 
-
     @Test
     public void testMeasuredEnergyBasedModel_multiDisplay() {
         mStatsRule.initMeasuredEnergyStatsLocked()
@@ -202,8 +193,6 @@
         // (600000000 + 800000000) uAs * (1 mA / 1000 uA) * (1 h / 3600 s)  = 166.66666 mAh
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(388.88888);
-        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         UidBatteryConsumer uid1 = mStatsRule.getUidBatteryConsumer(APP_UID1);
         assertThat(uid1.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
@@ -214,8 +203,6 @@
         // Uid1 charge = 20 / 80 * 600000000 mAs = 41.66666 mAh
         assertThat(uid1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(41.66666);
-        assertThat(uid1.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         UidBatteryConsumer uid2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
         assertThat(uid2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
@@ -226,17 +213,12 @@
         // Uid1 charge = 60 / 80 * 600000000 + 800000000 mAs = 347.22222 mAh
         assertThat(uid2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(347.22222);
-        assertThat(uid2.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
         assertThat(appsConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isEqualTo(110 * MINUTE_IN_MS);
         assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(388.88888);
-        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
-
     }
 
     @Test
@@ -277,8 +259,6 @@
         // Uid1 charge = 20 / 80 * 92.0 = 23.0 mAh
         assertThat(uid1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(23.0);
-        assertThat(uid1.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         UidBatteryConsumer uid2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
         assertThat(uid2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
@@ -288,27 +268,20 @@
         // Uid2 charge = 60 / 80 * 92.0 = 69.0 mAh
         assertThat(uid2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(69.0);
-        assertThat(uid2.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
         assertThat(deviceConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isEqualTo(80 * MINUTE_IN_MS);
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(92);
-        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
         assertThat(appsConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isEqualTo(80 * MINUTE_IN_MS);
         assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(92);
-        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
     }
 
-
     @Test
     public void testPowerProfileBasedModel_multiDisplay() {
         mStatsRule.setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, 1, 60.0)
@@ -364,8 +337,6 @@
         // 92 + 60 * 0.5 + 10 * 0.1 + 90 * 0.2 + 30 * 0.2 = 147
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(147);
-        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         UidBatteryConsumer uid1 = mStatsRule.getUidBatteryConsumer(APP_UID1);
         assertThat(uid1.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
@@ -375,8 +346,6 @@
         // Uid1 charge = 20 / 110 * 147.0 = 23.0 mAh
         assertThat(uid1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(26.72727);
-        assertThat(uid1.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         UidBatteryConsumer uid2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
         assertThat(uid2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
@@ -386,17 +355,12 @@
         // Uid2 charge = 90 / 110 * 92.0 = 69.0 mAh
         assertThat(uid2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(120.272727);
-        assertThat(uid2.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
         assertThat(appsConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isEqualTo(110 * MINUTE_IN_MS);
         assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(147);
-        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
-
     }
 
     private void setProcState(int uid, int procState, boolean resumed, long realtimeMs,
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java
index ef0b570..1ff347f 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java
@@ -31,8 +31,6 @@
 import android.platform.test.annotations.RequiresFlagsDisabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
-import android.platform.test.flag.junit.RavenwoodFlagsValueProvider;
-import android.platform.test.ravenwood.RavenwoodRule;
 
 import androidx.test.filters.SmallTest;
 
@@ -58,18 +56,13 @@
 @SuppressWarnings("GuardedBy")
 public class SystemServicePowerCalculatorTest {
     @Rule(order = 0)
-    public final RavenwoodRule mRavenwood = new RavenwoodRule();
-
-    @Rule(order = 1)
-    public final CheckFlagsRule mCheckFlagsRule = RavenwoodRule.isOnRavenwood()
-            ? RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule()
-            : DeviceFlagsValueProvider.createCheckFlagsRule();
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
 
     private static final double PRECISION = 0.000001;
     private static final int APP_UID1 = 100;
     private static final int APP_UID2 = 200;
 
-    @Rule(order = 2)
+    @Rule(order = 1)
     public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
             .setAveragePower(PowerProfile.POWER_CPU_ACTIVE, 720)
             .setCpuScalingPolicy(0, new int[]{0, 1}, new int[]{100, 200})
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerCalculatorTest.java
index 8e221be..827d2f8 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerCalculatorTest.java
@@ -159,22 +159,16 @@
                 .isEqualTo(2473);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isWithin(PRECISION).of(0.3964);
-        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
         assertThat(deviceConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isEqualTo(4001);
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isWithin(PRECISION).of(0.86666);
-        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         BatteryConsumer appsConsumer = mStatsRule.getDeviceBatteryConsumer();
         assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isWithin(PRECISION).of(0.866666);
-        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
     }
 
     @Test
@@ -214,8 +208,6 @@
                 .isEqualTo(12423);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isWithin(PRECISION).of(2.0214666);
-        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         final BatteryConsumer.Key foreground = uidConsumer.getKey(
                 BatteryConsumer.POWER_COMPONENT_WIFI,
@@ -248,22 +240,16 @@
         /* Same ratio as in testPowerControllerBasedModel_nonMeasured but scaled by 1_000_000uC. */
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isWithin(PRECISION).of(0.2214666 / (0.2214666 + 0.645200) * 1_000_000 / 3600000);
-        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
         assertThat(deviceConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isEqualTo(4002);
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isWithin(PRECISION).of(0.27777);
-        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         BatteryConsumer appsConsumer = mStatsRule.getDeviceBatteryConsumer();
         assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isWithin(PRECISION).of(0.277777);
-        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
     }
 
     @Test
@@ -302,8 +288,6 @@
                 .isEqualTo(12423);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isWithin(PRECISION).of(1.0325211);
-        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         final BatteryConsumer.Key foreground = uidConsumer.getKey(
                 BatteryConsumer.POWER_COMPONENT_WIFI,
@@ -349,8 +333,6 @@
                 .isEqualTo(1000);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isWithin(PRECISION).of(0.8231573);
-        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
     }
 
     @Test
@@ -371,8 +353,6 @@
         /* Same ratio as in testTimerBasedModel_nonMeasured but scaled by 1_000_000uC. */
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isWithin(PRECISION).of(0.8231573 / (0.8231573 + 0.8759216) * 1_000_000 / 3600000);
-        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
-                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
     }
 
     private WifiActivityEnergyInfo buildWifiActivityEnergyInfo(long timeSinceBoot,
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/BasePowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/BasePowerStatsProcessorTest.java
index f7a1638..cca6033 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/BasePowerStatsProcessorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/BasePowerStatsProcessorTest.java
@@ -176,7 +176,6 @@
                 powerStatsAggregator, /* batterySessionTimeSpanSlackMillis */ 0);
 
         BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(new String[0],
-                /* includePowerModels */ false,
                 /* includeProcessStateData */ true,
                 /* includeScreenStateData */ true,
                 /* includesPowerStateData */ true,
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java
index 4643ddd..38fe613 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java
@@ -342,7 +342,7 @@
         PowerStatsExporter exporter = new PowerStatsExporter(mPowerStatsStore,
                 mPowerStatsAggregator, /* batterySessionTimeSpanSlackMillis */ 0);
 
-        BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(new String[0], false,
+        BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(new String[0],
                 includeProcessStateData, includeScreenStateData, includesPowerStateData, 0);
         exporter.populateBatteryUsageStatsBuilder(builder, aps);
         return builder.build();
@@ -361,7 +361,7 @@
     private void breakdownByProcState_fullRange(boolean includeScreenStateData,
             boolean includePowerStateData) throws Exception {
         BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
-                new String[]{"cu570m"}, /* includePowerModels */ false,
+                new String[]{"cu570m"},
                 /* includeProcessStateData */ true, includeScreenStateData,
                 includePowerStateData, /* powerThreshold */ 0);
         exportAggregatedPowerStats(builder, 1000, 10000);
@@ -406,7 +406,7 @@
     @Test
     public void breakdownByProcState_subRange() throws Exception {
         BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
-                new String[]{"cu570m"}, /* includePowerModels */ false,
+                new String[]{"cu570m"},
                 /* includeProcessStateData */ true, true, true, /* powerThreshold */ 0);
         exportAggregatedPowerStats(builder, 3700, 6700);
 
@@ -438,7 +438,7 @@
     @Test
     public void combinedProcessStates() throws Exception {
         BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
-                new String[]{"cu570m"}, /* includePowerModels */ false,
+                new String[]{"cu570m"},
                 /* includeProcessStateData */ false, true, true, /* powerThreshold */ 0);
         exportAggregatedPowerStats(builder, 1000, 10000);
 
diff --git a/services/tests/security/intrusiondetection/Android.bp b/services/tests/security/intrusiondetection/Android.bp
index 00ac908..8d674b1 100644
--- a/services/tests/security/intrusiondetection/Android.bp
+++ b/services/tests/security/intrusiondetection/Android.bp
@@ -19,15 +19,20 @@
         "androidx.test.rules",
         "androidx.test.runner",
         "compatibility-device-util-axt",
+        "coretests-aidl",
         "frameworks-base-testutils",
         "junit",
         "platform-test-annotations",
+        "servicestests-utils",
         "services.core",
         "truth",
         "Nene",
         "Harrier",
         "TestApp",
     ],
+    data: [
+        ":TestIntrusionDetectionApp",
+    ],
 
     platform_apis: true,
 
diff --git a/services/tests/security/intrusiondetection/AndroidManifest.xml b/services/tests/security/intrusiondetection/AndroidManifest.xml
index f388e7e..b30710d 100644
--- a/services/tests/security/intrusiondetection/AndroidManifest.xml
+++ b/services/tests/security/intrusiondetection/AndroidManifest.xml
@@ -18,12 +18,25 @@
   package="com.android.server.security.intrusiondetection.tests">
 
        <uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING"     />
-       <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
+       <uses-permission android:name="android.permission.INTERNET"/>
 
-    <application android:testOnly="true">
+    <application android:testOnly="true" android:debuggable="true" android:usesCleartextTraffic="true">
       <uses-library android:name="android.test.runner"/>
+        <receiver android:name="com.android.server.security.intrusiondetection.IntrusionDetectionAdminReceiver"
+             android:permission="android.permission.BIND_DEVICE_ADMIN"
+             android:exported="true">
+            <meta-data android:name="android.app.device_admin"
+                 android:resource="@xml/device_admin"/>
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
+            </intent-filter>
+        </receiver>
     </application>
 
+    <queries>
+        <package android:name="com.android.coretests.apps.testapp" />
+    </queries>
+
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
          android:targetPackage="com.android.server.security.intrusiondetection.tests"
          android:label="Frameworks IntrusionDetection Services Tests"/>
diff --git a/services/tests/security/intrusiondetection/AndroidTest.xml b/services/tests/security/intrusiondetection/AndroidTest.xml
index 42cb9e3..6489dea4a 100644
--- a/services/tests/security/intrusiondetection/AndroidTest.xml
+++ b/services/tests/security/intrusiondetection/AndroidTest.xml
@@ -20,6 +20,7 @@
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true"/>
         <option name="test-file-name" value="IntrusionDetectionServiceTests.apk"/>
+        <option name="test-file-name" value="TestIntrusionDetectionApp.apk"/>
         <option name="install-arg" value="-t" />
     </target_preparer>
 
diff --git a/services/tests/security/intrusiondetection/res/xml/device_admin.xml b/services/tests/security/intrusiondetection/res/xml/device_admin.xml
new file mode 100644
index 0000000..f8cd8f0
--- /dev/null
+++ b/services/tests/security/intrusiondetection/res/xml/device_admin.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
+</device-admin>
diff --git a/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java
index bc854cf..e505ebe 100644
--- a/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java
+++ b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java
@@ -16,14 +16,19 @@
 
 package com.android.server.security.intrusiondetection;
 
+import static android.Manifest.permission.INTERNET;
 import static android.Manifest.permission.MANAGE_INTRUSION_DETECTION_STATE;
 import static android.Manifest.permission.READ_INTRUSION_DETECTION_STATE;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
@@ -33,8 +38,14 @@
 import android.annotation.SuppressLint;
 import android.app.admin.ConnectEvent;
 import android.app.admin.DnsEvent;
+import android.app.admin.SecurityLog;
 import android.app.admin.SecurityLog.SecurityEvent;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.Bundle;
 import android.os.Looper;
 import android.os.PermissionEnforcer;
 import android.os.RemoteException;
@@ -43,19 +54,47 @@
 import android.security.intrusiondetection.IIntrusionDetectionServiceCommandCallback;
 import android.security.intrusiondetection.IIntrusionDetectionServiceStateCallback;
 import android.security.intrusiondetection.IntrusionDetectionEvent;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.util.Log;
 
 import androidx.test.core.app.ApplicationProvider;
 
+import com.android.bedstead.harrier.BedsteadJUnit4;
+import com.android.bedstead.harrier.annotations.AfterClass;
+import com.android.bedstead.harrier.annotations.BeforeClass;
+import com.android.bedstead.multiuser.annotations.RequireRunOnSystemUser;
+import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.devicepolicy.DeviceOwner;
+import com.android.bedstead.nene.exceptions.NeneException;
+import com.android.bedstead.permissions.CommonPermissions;
+import com.android.bedstead.permissions.PermissionContext;
+import com.android.bedstead.permissions.annotations.EnsureHasPermission;
+import com.android.coretests.apps.testapp.LocalIntrusionDetectionEventTransport;
+import com.android.internal.infra.AndroidFuture;
 import com.android.server.ServiceThread;
 
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
+@RunWith(BedsteadJUnit4.class)
 public class IntrusionDetectionServiceTest {
     private static final int STATE_UNKNOWN =
             IIntrusionDetectionServiceStateCallback.State.UNKNOWN;
@@ -73,20 +112,49 @@
     private static final int ERROR_DATA_SOURCE_UNAVAILABLE =
             IIntrusionDetectionServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE;
 
+    private static DeviceOwner sDeviceOwner;
+
     private Context mContext;
     private IntrusionDetectionEventTransportConnection mIntrusionDetectionEventTransportConnection;
     private DataAggregator mDataAggregator;
     private IntrusionDetectionService mIntrusionDetectionService;
+    private IBinder mService;
     private TestLooper mTestLooper;
     private Looper mLooper;
     private TestLooper mTestLooperOfDataAggregator;
     private Looper mLooperOfDataAggregator;
     private FakePermissionEnforcer mPermissionEnforcer;
+    private boolean mBoundToLoggingService = false;
+    private static final String TEST_PKG =
+        "com.android.coretests.apps.testapp";
+    private static final String TEST_SERVICE = TEST_PKG + ".TestLoggingService";
+
+    @BeforeClass
+    public static void setDeviceOwner() {
+        ComponentName admin =
+                new ComponentName(
+                        ApplicationProvider.getApplicationContext(),
+                        IntrusionDetectionAdminReceiver.class);
+        try {
+            sDeviceOwner = TestApis.devicePolicy().setDeviceOwner(admin);
+        } catch (NeneException e) {
+            fail("Failed to set device owner " + admin.flattenToString() + ": " + e);
+        }
+    }
+
+    @AfterClass
+    public static void removeDeviceOwner() {
+        try {
+            sDeviceOwner.remove();
+        } catch (NeneException e) {
+            fail("Failed to remove device owner : " + e);
+        }
+    }
 
     @SuppressLint("VisibleForTests")
     @Before
-    public void setUp() {
-        mContext = spy(ApplicationProvider.getApplicationContext());
+    public void setUp() throws Exception {
+        mContext = ApplicationProvider.getApplicationContext();
 
         mPermissionEnforcer = new FakePermissionEnforcer();
         mPermissionEnforcer.grant(READ_INTRUSION_DETECTION_STATE);
@@ -343,6 +411,234 @@
         assertNotNull(receivedEvents.get(2).getDnsEvent());
     }
 
+    @Test
+    @RequireRunOnSystemUser
+    public void testDataSources_Initialize_HasDeviceOwner() throws Exception {
+        NetworkLogSource networkLogSource = new NetworkLogSource(mContext, mDataAggregator);
+        SecurityLogSource securityLogSource = new SecurityLogSource(mContext, mDataAggregator);
+
+        assertTrue(networkLogSource.initialize());
+        assertTrue(securityLogSource.initialize());
+    }
+
+    @Test
+    @RequireRunOnSystemUser
+    public void testDataSources_Initialize_NoDeviceOwner() throws Exception {
+        NetworkLogSource networkLogSource = new NetworkLogSource(mContext, mDataAggregator);
+        SecurityLogSource securityLogSource = new SecurityLogSource(mContext, mDataAggregator);
+        ComponentName admin = sDeviceOwner.componentName();
+
+        try {
+            sDeviceOwner.remove();
+            assertFalse(networkLogSource.initialize());
+            assertFalse(securityLogSource.initialize());
+        } finally {
+            sDeviceOwner = TestApis.devicePolicy().setDeviceOwner(admin);
+        }
+    }
+
+    @Test
+    @RequireRunOnSystemUser
+    @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
+    public void testDataAggregator_AddSecurityEvent() throws Exception {
+        mIntrusionDetectionService.setState(STATE_ENABLED);
+        ServiceThread mockThread = spy(ServiceThread.class);
+        mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread);
+        assertTrue(mDataAggregator.initialize());
+
+        // SecurityLogging generates a number of events and callbacks, so create a latch to wait for
+        // the given event.
+        String eventString = this.getClass().getName() + ".testSecurityEvent";
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        // TODO: Replace this mock when the IntrusionDetectionEventTransportConnection is ready.
+        doAnswer(
+                    new Answer<Boolean>() {
+                        @Override
+                        public Boolean answer(InvocationOnMock input) {
+                            List<IntrusionDetectionEvent> receivedEvents =
+                                    (List<IntrusionDetectionEvent>) input.getArguments()[0];
+                            for (IntrusionDetectionEvent event : receivedEvents) {
+                                if (event.getType() == IntrusionDetectionEvent.SECURITY_EVENT) {
+                                    SecurityEvent securityEvent = event.getSecurityEvent();
+                                    Object[] eventData = (Object[]) securityEvent.getData();
+                                    if (securityEvent.getTag() == SecurityLog.TAG_KEY_GENERATED
+                                            && eventData[1].equals(eventString)) {
+                                        latch.countDown();
+                                    }
+                                }
+                            }
+                            return true;
+                        }
+                    })
+            .when(mIntrusionDetectionEventTransportConnection).addData(any());
+        mDataAggregator.enable();
+
+        // Generate the security event.
+        generateSecurityEvent(eventString);
+        TestApis.devicePolicy().forceSecurityLogs();
+
+        // Verify the event is received.
+        mTestLooper.startAutoDispatch();
+        assertTrue(latch.await(1, TimeUnit.SECONDS));
+        mTestLooper.stopAutoDispatch();
+
+        mDataAggregator.disable();
+    }
+
+    @Test
+    @RequireRunOnSystemUser
+    @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
+    public void testDataAggregator_AddNetworkEvent() throws Exception {
+        mIntrusionDetectionService.setState(STATE_ENABLED);
+        ServiceThread mockThread = spy(ServiceThread.class);
+        mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread);
+        assertTrue(mDataAggregator.initialize());
+
+        // Network logging may log multiple and callbacks, so create a latch to wait for
+        // the given event.
+        // eventServer must be a valid domain to generate a network log event.
+        String eventServer = "google.com";
+        final CountDownLatch latch = new CountDownLatch(1);
+        // TODO: Replace this mock when the IntrusionDetectionEventTransportConnection is ready.
+        doAnswer(
+                    new Answer<Boolean>() {
+                        @Override
+                        public Boolean answer(InvocationOnMock input) {
+                            List<IntrusionDetectionEvent> receivedEvents =
+                                    (List<IntrusionDetectionEvent>) input.getArguments()[0];
+                            for (IntrusionDetectionEvent event : receivedEvents) {
+                                if (event.getType()
+                                        == IntrusionDetectionEvent.NETWORK_EVENT_DNS) {
+                                    DnsEvent dnsEvent = event.getDnsEvent();
+                                    if (dnsEvent.getHostname().equals(eventServer)) {
+                                        latch.countDown();
+                                    }
+                                }
+                            }
+                            return true;
+                        }
+                    })
+            .when(mIntrusionDetectionEventTransportConnection).addData(any());
+        mDataAggregator.enable();
+
+        // Generate the network event.
+        generateNetworkEvent(eventServer);
+        TestApis.devicePolicy().forceNetworkLogs();
+
+        // Verify the event is received.
+        mTestLooper.startAutoDispatch();
+        assertTrue(latch.await(1, TimeUnit.SECONDS));
+        mTestLooper.stopAutoDispatch();
+
+        mDataAggregator.disable();
+    }
+
+    /** Emits a given string into security log (if enabled). */
+    private void generateSecurityEvent(String eventString)
+            throws IllegalArgumentException, GeneralSecurityException, IOException {
+        if (eventString == null || eventString.isEmpty()) {
+            throw new IllegalArgumentException(
+                    "Error generating security event: eventString must not be empty");
+        }
+
+        final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
+        keyGen.initialize(
+                new KeyGenParameterSpec.Builder(eventString, KeyProperties.PURPOSE_SIGN).build());
+        // Emit key generation event.
+        final KeyPair keyPair = keyGen.generateKeyPair();
+        assertNotNull(keyPair);
+
+        final KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
+        ks.load(null);
+        // Emit key destruction event.
+        ks.deleteEntry(eventString);
+    }
+
+    /** Emits a given string into network log (if enabled). */
+    private void generateNetworkEvent(String server) throws IllegalArgumentException, IOException {
+        if (server == null || server.isEmpty()) {
+            throw new IllegalArgumentException(
+                    "Error generating network event: server must not be empty");
+        }
+
+        HttpURLConnection urlConnection = null;
+        int connectionTimeoutMS = 2_000;
+        try (PermissionContext p = TestApis.permissions().withPermission(INTERNET)) {
+            final URL url = new URL("http://" + server);
+            urlConnection = (HttpURLConnection) url.openConnection();
+            urlConnection.setConnectTimeout(connectionTimeoutMS);
+            urlConnection.setReadTimeout(connectionTimeoutMS);
+            urlConnection.getResponseCode();
+        } finally {
+            if (urlConnection != null) {
+                urlConnection.disconnect();
+            }
+        }
+    }
+
+    @Test
+    public void test_StartIntrusionDetectionEventTransportService() {
+        final String TAG = "test_StartIntrusionDetectionEventTransportService";
+        ServiceConnection serviceConnection = null;
+
+        assertEquals(false, mBoundToLoggingService);
+        try {
+            serviceConnection = startTestService();
+            assertEquals(true, mBoundToLoggingService);
+            assertNotNull(serviceConnection);
+        } catch (SecurityException e) {
+            Log.e(TAG, "SecurityException while starting: ", e);
+            fail("Exception thrown while connecting to service");
+        } catch (InterruptedException e) {
+            Log.e(TAG, "InterruptedException while starting: ", e);
+            fail("Interrupted while connecting to service");
+        } finally {
+            mContext.unbindService(serviceConnection);
+        }
+    }
+
+    private ServiceConnection startTestService() throws SecurityException, InterruptedException {
+        final String TAG = "startTestService";
+        final CountDownLatch latch = new CountDownLatch(1);
+        LocalIntrusionDetectionEventTransport transport =
+                new LocalIntrusionDetectionEventTransport();
+
+        ServiceConnection serviceConnection = new ServiceConnection() {
+            // Called when connection with the service is established.
+            @Override
+            public void onServiceConnected(ComponentName className, IBinder service) {
+                mService = transport.getBinder();
+                mBoundToLoggingService = true;
+                latch.countDown();
+            }
+
+            // Called when the connection with the service disconnects unexpectedly.
+            @Override
+            public void onServiceDisconnected(ComponentName className) {
+                Log.d(TAG, "onServiceDisconnected");
+                mBoundToLoggingService = false;
+            }
+        };
+
+        Intent intent = new Intent();
+        intent.setComponent(new ComponentName(TEST_PKG, TEST_SERVICE));
+        mContext.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
+        latch.await(5, TimeUnit.SECONDS);
+
+        // call the methods on the transport object
+        IntrusionDetectionEvent event =
+                new IntrusionDetectionEvent(new SecurityEvent(123, new byte[15]));
+        List<IntrusionDetectionEvent> events = new ArrayList<>();
+        events.add(event);
+        assertTrue(transport.initialize());
+        assertTrue(transport.addData(events));
+        assertTrue(transport.release());
+        assertEquals(1, transport.getEvents().size());
+
+        return serviceConnection;
+    }
+
     private class MockInjector implements IntrusionDetectionService.Injector {
         private final Context mContext;
 
diff --git a/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/TestApp/src/com/android/coretests/apps/testapp/Android.bp b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/TestApp/src/com/android/coretests/apps/testapp/Android.bp
new file mode 100644
index 0000000..ca5952b
--- /dev/null
+++ b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/TestApp/src/com/android/coretests/apps/testapp/Android.bp
@@ -0,0 +1,42 @@
+// 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 {
+    default_team: "trendy_team_platform_security",
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test_helper_app {
+    name: "TestIntrusionDetectionApp",
+
+    static_libs: [
+        "frameworks-base-testutils",
+        "services.core",
+        "servicestests-utils",
+    ],
+
+    srcs: ["**/*.java"],
+
+    platform_apis: true,
+    certificate: "platform",
+    dxflags: ["--multi-dex"],
+    optimize: {
+        enabled: false,
+    },
+}
diff --git a/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/TestApp/src/com/android/coretests/apps/testapp/AndroidManifest.xml b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/TestApp/src/com/android/coretests/apps/testapp/AndroidManifest.xml
new file mode 100644
index 0000000..7cc75ab
--- /dev/null
+++ b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/TestApp/src/com/android/coretests/apps/testapp/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.coretests.apps.testapp">
+
+    <application>
+        <service android:name=".TestLoggingService"
+                  android:exported="true" />
+    </application>
+</manifest>
\ No newline at end of file
diff --git a/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/TestApp/src/com/android/coretests/apps/testapp/LocalIntrusionDetectionEventTransport.java b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/TestApp/src/com/android/coretests/apps/testapp/LocalIntrusionDetectionEventTransport.java
new file mode 100644
index 0000000..f0012da
--- /dev/null
+++ b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/TestApp/src/com/android/coretests/apps/testapp/LocalIntrusionDetectionEventTransport.java
@@ -0,0 +1,58 @@
+/*
+ * 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.coretests.apps.testapp;
+
+import android.security.intrusiondetection.IntrusionDetectionEvent;
+import android.security.intrusiondetection.IntrusionDetectionEventTransport;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A class that extends {@link IntrusionDetectionEventTransport} to provide a
+ * local transport mechanism for testing purposes. This implementation overrides
+ * the {@link #initialize()}, {@link #addData(List)}, and {@link #release()} methods
+ * to manage events locally within the test environment.
+ *
+ * For now, the implementation returns true for all methods since we don't
+ * have a real data source to send events to.
+ */
+public class LocalIntrusionDetectionEventTransport extends IntrusionDetectionEventTransport {
+    private List<IntrusionDetectionEvent> mEvents = new ArrayList<>();
+
+    @Override
+    public boolean initialize() {
+        return true;
+    }
+
+    @Override
+    public boolean addData(List<IntrusionDetectionEvent> events) {
+        mEvents.addAll(events);
+        return true;
+    }
+
+    @Override
+    public boolean release() {
+        return true;
+    }
+
+    public List<IntrusionDetectionEvent> getEvents() {
+        return mEvents;
+    }
+}
\ No newline at end of file
diff --git a/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/TestApp/src/com/android/coretests/apps/testapp/TestLoggingService.java b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/TestApp/src/com/android/coretests/apps/testapp/TestLoggingService.java
new file mode 100644
index 0000000..e4bf987
--- /dev/null
+++ b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/TestApp/src/com/android/coretests/apps/testapp/TestLoggingService.java
@@ -0,0 +1,40 @@
+/*
+ * 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.coretests.apps.testapp;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.Process;
+
+import com.android.internal.infra.AndroidFuture;
+
+
+public class TestLoggingService extends Service {
+    private static final String TAG = "TestLoggingService";
+    private LocalIntrusionDetectionEventTransport mLocalIntrusionDetectionEventTransport;
+
+    public TestLoggingService() {
+        mLocalIntrusionDetectionEventTransport = new LocalIntrusionDetectionEventTransport();
+    }
+
+    // Binder given to clients.
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mLocalIntrusionDetectionEventTransport.getBinder();
+    }
+}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 0c058df..009ce88 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -897,16 +897,6 @@
 }
 
 test_module_config {
-    name: "FrameworksServicesTests_server_accessibility",
-    base: "FrameworksServicesTests",
-    test_suites: [
-        "automotive-tests",
-        "device-tests",
-    ],
-    include_filters: ["com.android.server.accessibility"],
-}
-
-test_module_config {
     name: "FrameworksServicesTests_server_binarytransparencyservicetest",
     base: "FrameworksServicesTests",
     test_suites: [
diff --git a/services/tests/servicestests/jni/Android.bp b/services/tests/servicestests/jni/Android.bp
index 0a31037..e738c19 100644
--- a/services/tests/servicestests/jni/Android.bp
+++ b/services/tests/servicestests/jni/Android.bp
@@ -22,9 +22,9 @@
     srcs: [
         ":lib_cachedAppOptimizer_native",
         ":lib_freezer_native",
-        ":lib_gameManagerService_native",
         ":lib_oomConnection_native",
         ":lib_anrTimer_native",
+        ":lib_lazilyRegisteredServices_native",
         "onload.cpp",
     ],
 
@@ -55,6 +55,8 @@
         "android.hardware.graphics.bufferqueue@2.0",
         "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.mapper@4.0",
+        "android.hardware.ir@1.0",
+        "android.hardware.vr@1.0",
         "android.hidl.token@1.0-utils",
     ],
 }
diff --git a/services/tests/servicestests/jni/onload.cpp b/services/tests/servicestests/jni/onload.cpp
index 25487c5..ad979c6 100644
--- a/services/tests/servicestests/jni/onload.cpp
+++ b/services/tests/servicestests/jni/onload.cpp
@@ -25,9 +25,9 @@
 
 namespace android {
 int register_android_server_am_CachedAppOptimizer(JNIEnv* env);
-int register_android_server_app_GameManagerService(JNIEnv* env);
 int register_android_server_am_OomConnection(JNIEnv* env);
 int register_android_server_utils_AnrTimer(JNIEnv *env);
+int register_android_server_utils_LazyJniRegistrar(JNIEnv* env);
 };
 
 using namespace android;
@@ -43,8 +43,8 @@
     }
     ALOG_ASSERT(env, "Could not retrieve the env!");
     register_android_server_am_CachedAppOptimizer(env);
-    register_android_server_app_GameManagerService(env);
     register_android_server_am_OomConnection(env);
     register_android_server_utils_AnrTimer(env);
+    register_android_server_utils_LazyJniRegistrar(env);
     return JNI_VERSION_1_4;
 }
diff --git a/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java b/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java
index ae78dfe..cc5be7e 100644
--- a/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java
@@ -20,6 +20,7 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
@@ -40,6 +41,7 @@
 import android.hardware.fingerprint.FingerprintSensorProperties;
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
 import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
+import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.SystemProperties;
@@ -50,6 +52,12 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import com.android.internal.util.FrameworkStatsLog;
+import com.android.internal.os.IBinaryTransparencyService;
+import com.android.server.pm.BackgroundInstallControlService;
+import com.android.server.pm.BackgroundInstallControlCallbackHelper;
+import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackageSplit;
+import com.android.server.pm.pkg.PackageStateInternal;
 
 import org.junit.After;
 import org.junit.Assert;
@@ -68,6 +76,9 @@
 public class BinaryTransparencyServiceTest {
     private static final String TAG = "BinaryTransparencyServiceTest";
 
+    private static final String TEST_PKG_NAME = "testPackageName";
+    private static final long TEST_VERSION_CODE = 1L;
+
     private Context mContext;
     private BinaryTransparencyService mBinaryTransparencyService;
     private BinaryTransparencyService.BinaryTransparencyServiceImpl mTestInterface;
@@ -83,6 +94,8 @@
     private PackageManager mPackageManager;
     @Mock
     private PackageManagerInternal mPackageManagerInternal;
+    @Mock
+    private BinaryTransparencyService.BicCallbackHandler.IBicAppInfoHelper mBicAppInfoHelper;
 
     @Captor
     private ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback>
@@ -91,6 +104,9 @@
     private ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback>
             mFaceAuthenticatorsRegisteredCaptor;
 
+    @Captor
+    private ArgumentCaptor<IBinaryTransparencyService.AppInfo> appInfoCaptor;
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
@@ -262,4 +278,69 @@
                 eq("") /* softwareVersion */
         );
     }
+
+    @Test
+    public void BicCallbackHandler_uploads_mba_metrics() {
+        Bundle data = setupBicCallbackHandlerTest(false,
+            BinaryTransparencyService.MBA_STATUS_NEW_INSTALL);
+
+        BinaryTransparencyService.BicCallbackHandler handler =
+            new BinaryTransparencyService.BicCallbackHandler(mBicAppInfoHelper);
+        handler.sendResult(data);
+
+        verify(mBicAppInfoHelper, times(1)).writeAppInfoToLog(appInfoCaptor.capture());
+        Assert.assertEquals(TEST_PKG_NAME, appInfoCaptor.getValue().packageName);
+        Assert.assertEquals(TEST_VERSION_CODE, appInfoCaptor.getValue().longVersion);
+    }
+
+    @Test
+    public void BicCallbackHandler_uploads_mba_metrics_for_preloads() {
+        Bundle data = setupBicCallbackHandlerTest(true,
+            BinaryTransparencyService.MBA_STATUS_UPDATED_PRELOAD);
+
+        BinaryTransparencyService.BicCallbackHandler handler =
+            new BinaryTransparencyService.BicCallbackHandler(mBicAppInfoHelper);
+        handler.sendResult(data);
+
+        verify(mBicAppInfoHelper, times(1)).writeAppInfoToLog(appInfoCaptor.capture());
+        Assert.assertEquals(TEST_PKG_NAME, appInfoCaptor.getValue().packageName);
+        Assert.assertEquals(TEST_VERSION_CODE, appInfoCaptor.getValue().longVersion);
+    }
+
+    @Test
+    public void BicCallbackHandler_uploads_mba_metrics_for_uninstalls() {
+        Bundle data = new Bundle();
+        data.putString(BackgroundInstallControlCallbackHelper.FLAGGED_PACKAGE_NAME_KEY,
+            TEST_PKG_NAME);
+        data.putInt(BackgroundInstallControlCallbackHelper.INSTALL_EVENT_TYPE_KEY,
+            BackgroundInstallControlService.INSTALL_EVENT_TYPE_UNINSTALL);
+
+        BinaryTransparencyService.BicCallbackHandler handler =
+                new BinaryTransparencyService.BicCallbackHandler(mBicAppInfoHelper);
+        handler.sendResult(data);
+
+        verify(mBicAppInfoHelper, times(1)).writeAppInfoToLog(appInfoCaptor.capture());
+        Assert.assertEquals(TEST_PKG_NAME ,appInfoCaptor.getValue().packageName);
+        Assert.assertEquals(BinaryTransparencyService.MBA_STATUS_UNINSTALLED,
+            appInfoCaptor.getValue().mbaStatus);
+    }
+
+    private Bundle setupBicCallbackHandlerTest(boolean isUpdatedSystemApp,
+            int expectedBtsMbaStatus) {
+        Bundle data = new Bundle();
+        data.putString(BackgroundInstallControlCallbackHelper.FLAGGED_PACKAGE_NAME_KEY,
+            TEST_PKG_NAME);
+        data.putInt(BackgroundInstallControlCallbackHelper.INSTALL_EVENT_TYPE_KEY,
+            BackgroundInstallControlService.INSTALL_EVENT_TYPE_INSTALL);
+        PackageStateInternal mockPackageState = mock(PackageStateInternal.class);
+        when(mPackageManagerInternal.getPackageStateInternal(TEST_PKG_NAME))
+            .thenReturn(mockPackageState);
+        when(mockPackageState.isUpdatedSystemApp()).thenReturn(isUpdatedSystemApp);
+        IBinaryTransparencyService.AppInfo appInfo = new IBinaryTransparencyService.AppInfo();
+        appInfo.packageName = TEST_PKG_NAME;
+        appInfo.longVersion = TEST_VERSION_CODE;
+        when(mBicAppInfoHelper.collectAppInfo(mockPackageState, expectedBtsMbaStatus))
+            .thenReturn(List.of(appInfo));
+        return data;
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 492838e9..08fdaf4 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -38,7 +38,6 @@
 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
 import static com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity.EXTRA_TYPE_TO_CHOOSE;
 import static com.android.server.accessibility.AccessibilityManagerService.ACTION_LAUNCH_HEARING_DEVICES_DIALOG;
-import static com.android.window.flags.Flags.FLAG_ALWAYS_DRAW_MAGNIFICATION_FULLSCREEN_BORDER;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -601,7 +600,6 @@
     }
 
     @Test
-    @EnableFlags(FLAG_ALWAYS_DRAW_MAGNIFICATION_FULLSCREEN_BORDER)
     public void testSetConnectionNull_borderFlagEnabled_unregisterFullScreenMagnification()
             throws RemoteException {
         mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
@@ -1817,9 +1815,7 @@
     }
 
     @Test
-    @EnableFlags({
-            android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE,
-            Flags.FLAG_CLEAR_DEFAULT_FROM_A11Y_SHORTCUT_TARGET_SERVICE_RESTORE})
+    @EnableFlags(android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE)
     public void restoreShortcutTargets_hardware_alreadyHadDefaultService_doesNotClear() {
         final String serviceDefault = TARGET_STANDARD_A11Y_SERVICE_NAME;
         mTestableContext.getOrCreateTestableResources().addOverride(
@@ -1845,9 +1841,7 @@
     }
 
     @Test
-    @EnableFlags({
-            android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE,
-            Flags.FLAG_CLEAR_DEFAULT_FROM_A11Y_SHORTCUT_TARGET_SERVICE_RESTORE})
+    @EnableFlags(android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE)
     public void restoreShortcutTargets_hardware_didNotHaveDefaultService_clearsDefaultService() {
         final String serviceDefault = TARGET_STANDARD_A11Y_SERVICE_NAME;
         final String serviceRestored = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
@@ -1872,9 +1866,7 @@
     }
 
     @Test
-    @EnableFlags({
-            android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE,
-            Flags.FLAG_CLEAR_DEFAULT_FROM_A11Y_SHORTCUT_TARGET_SERVICE_RESTORE})
+    @EnableFlags(Flags.FLAG_CLEAR_DEFAULT_FROM_A11Y_SHORTCUT_TARGET_SERVICE_RESTORE)
     public void restoreShortcutTargets_hardware_nullSetting_clearsDefaultService() {
         final String serviceDefault = TARGET_STANDARD_A11Y_SERVICE_NAME;
         final String serviceRestored = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
index 403930d..2ae31ad 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -18,20 +18,24 @@
 
 import static com.android.server.accessibility.AbstractAccessibilityServiceConnection.DISPLAY_TYPE_DEFAULT;
 import static com.android.server.accessibility.AccessibilityWindowManagerTest.DisplayIdMatcher.displayId;
+import static com.android.server.accessibility.AccessibilityWindowManagerTest.EventWindowIdMatcher.eventWindowId;
 import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowChangesMatcher.a11yWindowChanges;
-import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowIdMatcher.a11yWindowId;
+import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowIdMatcher.windowId;
 
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.not;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
@@ -42,14 +46,13 @@
 import static org.mockito.Mockito.when;
 
 import android.annotation.Nullable;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.IBinder;
 import android.os.LocaleList;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.platform.test.annotations.RequiresFlagsDisabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.IWindow;
@@ -63,6 +66,7 @@
 
 import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
 import com.android.server.accessibility.test.MessageCapturingHandler;
+import com.android.server.wm.AccessibilityWindowsPopulator.AccessibilityWindow;
 import com.android.server.wm.WindowManagerInternal;
 import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
 
@@ -70,7 +74,6 @@
 import org.hamcrest.TypeSafeMatcher;
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
@@ -81,17 +84,9 @@
 import java.util.Arrays;
 import java.util.List;
 
-// This test verifies deprecated codepath. Probably changing this file means
-// AccessibilityWindowManagerWithAccessibilityWindowTest also needs to be updated.
-// LINT.IfChange
-
 /**
- * Tests for the AccessibilityWindowManager with Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2
- * enabled.
- * TODO(b/322444245): Merge with AccessibilityWindowManagerWithAccessibilityWindowTest
- *  after completing the flag migration.
+ * Tests for the AccessibilityWindowManager.
  */
-@RequiresFlagsDisabled(Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2)
 public class AccessibilityWindowManagerTest {
     private static final String PACKAGE_NAME = "com.android.server.accessibility";
     private static final boolean FORCE_SEND = true;
@@ -122,9 +117,8 @@
 
     // List of window token, mapping from windowId -> window token.
     private final SparseArray<IWindow> mA11yWindowTokens = new SparseArray<>();
-    // List of window info lists, mapping from displayId -> window info lists.
-    private final SparseArray<ArrayList<WindowInfo>> mWindowInfos =
-            new SparseArray<>();
+    // List of window info lists, mapping from displayId -> a11y window lists.
+    private final SparseArray<ArrayList<AccessibilityWindow>> mWindows = new SparseArray<>();
     // List of callback, mapping from displayId -> callback.
     private final SparseArray<WindowsForAccessibilityCallback> mCallbackOfWindows =
             new SparseArray<>();
@@ -134,6 +128,13 @@
 
     private final MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
 
+    // This maps displayId -> next region offset.
+    // Touchable region must have un-occluded area so that it's exposed to a11y services.
+    // This offset can be used as left and top of new region so that top-left of each region are
+    // kept visible.
+    // It's expected to be incremented by some amount everytime the value is used.
+    private final SparseArray<Integer> mNextRegionOffsets = new SparseArray<>();
+
     @Mock private WindowManagerInternal mMockWindowManagerInternal;
     @Mock private AccessibilityWindowManager.AccessibilityEventSender mMockA11yEventSender;
     @Mock private AccessibilitySecurityPolicy mMockA11ySecurityPolicy;
@@ -144,9 +145,6 @@
     @Mock private IBinder mMockEmbeddedToken;
     @Mock private IBinder mMockInvalidToken;
 
-    @Rule
-    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-
     @Before
     public void setUp() throws RemoteException {
         MockitoAnnotations.initMocks(this);
@@ -159,7 +157,7 @@
                 anyString(), anyInt(), anyInt(), anyInt())).thenReturn(PACKAGE_NAME);
 
         doAnswer((invocation) -> {
-            onWindowsForAccessibilityChanged(invocation.getArgument(0), false);
+            onAccessibilityWindowsChanged(invocation.getArgument(0), false);
             return null;
         }).when(mMockWindowManagerInternal).computeWindowsForAccessibility(anyInt());
 
@@ -173,7 +171,7 @@
         // as top focused display before each testing starts.
         startTrackingPerDisplay(Display.DEFAULT_DISPLAY);
 
-        // AccessibilityEventSender is invoked during onWindowsForAccessibilityChanged.
+        // AccessibilityEventSender is invoked during onAccessibilityWindowsChanged.
         // Resets it for mockito verify of further test case.
         Mockito.reset(mMockA11yEventSender);
 
@@ -237,19 +235,18 @@
     @Test
     public void onWindowsChanged_duringTouchInteractAndFocusChange_shouldChangeActiveWindow() {
         final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
-        WindowInfo focusedWindowInfo =
-                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX);
+        final WindowInfo focusedWindowInfo =
+                mWindows.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).getWindowInfo();
         assertEquals(activeWindowId, mA11yWindowManager.findWindowIdLocked(
                 USER_SYSTEM_ID, focusedWindowInfo.token));
 
         focusedWindowInfo.focused = false;
-        focusedWindowInfo =
-                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1);
-        focusedWindowInfo.focused = true;
+        mWindows.get(Display.DEFAULT_DISPLAY).get(
+                DEFAULT_FOCUSED_INDEX + 1).getWindowInfo().focused = true;
 
         mA11yWindowManager.onTouchInteractionStart();
         setTopFocusedWindowAndDisplay(Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX + 1);
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
 
         assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
     }
@@ -273,7 +270,7 @@
         changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID,
                 DEFAULT_FOCUSED_INDEX + 1, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX);
 
-        onWindowsForAccessibilityChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
+        onAccessibilityWindowsChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
         // The active window should not be changed.
         assertEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
         // The top focused window should not be changed.
@@ -301,8 +298,8 @@
         changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID,
                 DEFAULT_FOCUSED_INDEX, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX);
 
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-        onWindowsForAccessibilityChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        onAccessibilityWindowsChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
         // The active window should be changed.
         assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
         // The top focused window should be changed.
@@ -312,53 +309,181 @@
 
     @Test
     public void onWindowsChanged_shouldReportCorrectLayer() {
-        // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup.
+        // AccessibilityWindowManager#onAccessibilityWindowsChanged already invoked in setup.
         List<AccessibilityWindowInfo> a11yWindows =
                 mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
         for (int i = 0; i < a11yWindows.size(); i++) {
             final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
-            final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i);
-            assertThat(mWindowInfos.get(Display.DEFAULT_DISPLAY).size() - windowInfo.layer - 1,
+            assertThat(mWindows.get(Display.DEFAULT_DISPLAY).size() - i - 1,
                     is(a11yWindow.getLayer()));
         }
     }
 
     @Test
     public void onWindowsChanged_shouldReportCorrectOrder() {
-        // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup.
+        // AccessibilityWindowManager#onAccessibilityWindowsChanged already invoked in setup.
         List<AccessibilityWindowInfo> a11yWindows =
                 mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
         for (int i = 0; i < a11yWindows.size(); i++) {
             final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
             final IBinder windowToken = mA11yWindowManager
                     .getWindowTokenForUserAndWindowIdLocked(USER_SYSTEM_ID, a11yWindow.getId());
-            final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i);
+            final WindowInfo windowInfo = mWindows.get(Display.DEFAULT_DISPLAY)
+                    .get(i).getWindowInfo();
             assertThat(windowToken, is(windowInfo.token));
         }
     }
 
     @Test
-    public void onWindowsChangedAndForceSend_shouldUpdateWindows() {
-        final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
-        final int correctLayer =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer();
-        windowInfo.layer += 1;
+    public void onWindowsChanged_shouldNotReportNonTouchableWindow() {
+        final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+        when(window.isTouchable()).thenReturn(false);
+        final int windowId = mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, window.getWindowInfo().token);
 
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
-        assertNotEquals(correctLayer,
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer());
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, not(hasItem(windowId(windowId))));
     }
 
     @Test
-    public void onWindowsChangedNoForceSend_layerChanged_shouldNotUpdateWindows() {
-        final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
-        final int correctLayer =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer();
-        windowInfo.layer += 1;
+    public void onWindowsChanged_shouldReportFocusedNonTouchableWindow() {
+        final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(
+                DEFAULT_FOCUSED_INDEX);
+        when(window.isTouchable()).thenReturn(false);
+        final int windowId = mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, window.getWindowInfo().token);
 
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-        assertEquals(correctLayer,
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer());
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, hasItem(windowId(windowId)));
+    }
+
+    @Test
+    public void onWindowsChanged_trustedFocusedNonTouchableWindow_shouldNotHideWindowsBelow() {
+        // Make the focused trusted un-touchable window fullscreen.
+        final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(
+                DEFAULT_FOCUSED_INDEX);
+        setRegionForMockAccessibilityWindow(window, new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+        when(window.isTouchable()).thenReturn(false);
+        when(window.isTrustedOverlay()).thenReturn(true);
+
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, hasSize(NUM_OF_WINDOWS));
+    }
+
+    @Test
+    public void onWindowsChanged_accessibilityOverlay_shouldNotHideWindowsBelow() {
+        // Make the a11y overlay window fullscreen.
+        final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+        setRegionForMockAccessibilityWindow(window, new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+        when(window.getType()).thenReturn(WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY);
+
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, hasSize(NUM_OF_WINDOWS));
+    }
+
+    @Test
+    public void onWindowsChanged_shouldReportFocusedWindowEvenIfOccluded() {
+        // Make the front window fullscreen.
+        final AccessibilityWindow frontWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+        setRegionForMockAccessibilityWindow(frontWindow,
+                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+        final int frontWindowId = mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, frontWindow.getWindowInfo().token);
+
+        final AccessibilityWindow focusedWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(
+                DEFAULT_FOCUSED_INDEX);
+        final int focusedWindowId = mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, focusedWindow.getWindowInfo().token);
+
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, hasSize(2));
+        assertThat(a11yWindows.get(0), windowId(frontWindowId));
+        assertThat(a11yWindows.get(1), windowId(focusedWindowId));
+    }
+
+    @Test
+    public void onWindowsChanged_embeddedWindows_shouldOnlyReportHost() throws RemoteException {
+        final Rect embeddingBounds = new Rect(0, 0, 200, 100);
+
+        // The embedded window comes front of the host window.
+        final IBinder embeddedWindowLeashToken = Mockito.mock(IBinder.class);
+        final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, embeddedWindowLeashToken, USER_SYSTEM_ID);
+        final AccessibilityWindow embeddedWindow = createMockAccessibilityWindow(
+                mA11yWindowTokens.get(embeddedWindowId), Display.DEFAULT_DISPLAY);
+        setRegionForMockAccessibilityWindow(embeddedWindow, new Region(embeddingBounds));
+        mWindows.get(Display.DEFAULT_DISPLAY).set(0, embeddedWindow);
+
+        final IBinder hostWindowLeashToken = Mockito.mock(IBinder.class);
+        final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, hostWindowLeashToken, USER_SYSTEM_ID);
+        final AccessibilityWindow hostWindow = createMockAccessibilityWindow(
+                mA11yWindowTokens.get(hostWindowId), Display.DEFAULT_DISPLAY);
+        setRegionForMockAccessibilityWindow(hostWindow, new Region(embeddingBounds));
+        mWindows.get(Display.DEFAULT_DISPLAY).set(1, hostWindow);
+
+        mA11yWindowManager.associateEmbeddedHierarchyLocked(
+                hostWindowLeashToken, embeddedWindowLeashToken);
+
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, not(hasItem(windowId(embeddedWindowId))));
+        assertThat(a11yWindows.get(0), windowId(hostWindowId));
+        final Rect bounds = new Rect();
+        a11yWindows.get(0).getBoundsInScreen(bounds);
+        assertEquals(bounds, embeddingBounds);
+    }
+
+    @Test
+    public void onWindowsChanged_shouldNotReportfullyOccludedWindow() {
+        final AccessibilityWindow frontWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+        setRegionForMockAccessibilityWindow(frontWindow, new Region(100, 100, 300, 300));
+        final int frontWindowId = mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, frontWindow.getWindowInfo().token);
+
+        // index 1 is focused. Let's use the next one for this test.
+        final AccessibilityWindow occludedWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(2);
+        setRegionForMockAccessibilityWindow(occludedWindow, new Region(150, 150, 250, 250));
+        final int occludedWindowId = mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, occludedWindow.getWindowInfo().token);
+
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, hasItem(windowId(frontWindowId)));
+        assertThat(a11yWindows, not(hasItem(windowId(occludedWindowId))));
+    }
+
+    @Test
+    public void onWindowsChangedAndForceSend_shouldUpdateWindows() {
+        assertNotEquals("new title",
+                toString(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)
+                        .get(0).getTitle()));
+
+        mWindows.get(Display.DEFAULT_DISPLAY).get(0).getWindowInfo().title = "new title";
+
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+        assertEquals("new title",
+                toString(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)
+                        .get(0).getTitle()));
     }
 
     @Test
@@ -368,14 +493,10 @@
                 mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0);
         final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
                 true, USER_SYSTEM_ID);
-        final WindowInfo windowInfo = WindowInfo.obtain();
-        windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
-        windowInfo.token = token.asBinder();
-        windowInfo.layer = 0;
-        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
-        mWindowInfos.get(Display.DEFAULT_DISPLAY).set(0, windowInfo);
+        mWindows.get(Display.DEFAULT_DISPLAY).set(0,
+                createMockAccessibilityWindow(token, Display.DEFAULT_DISPLAY));
 
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
         assertNotEquals(oldWindow,
                 mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0));
     }
@@ -383,12 +504,12 @@
     @Test
     public void onWindowsChangedNoForceSend_focusChanged_shouldUpdateWindows() {
         final WindowInfo focusedWindowInfo =
-                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX);
-        final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+                mWindows.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).getWindowInfo();
+        final WindowInfo windowInfo = mWindows.get(Display.DEFAULT_DISPLAY).get(0).getWindowInfo();
         focusedWindowInfo.focused = false;
         windowInfo.focused = true;
 
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
         assertTrue(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0)
                 .isFocused());
     }
@@ -497,15 +618,18 @@
     @Test
     public void computePartialInteractiveRegionForWindow_wholeVisible_returnWholeRegion() {
         // Updates top 2 z-order WindowInfo are whole visible.
-        WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
-        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
-        windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1);
-        windowInfo.regionInScreen.set(0, SCREEN_HEIGHT / 2,
-                SCREEN_WIDTH, SCREEN_HEIGHT);
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+        setRegionForMockAccessibilityWindow(firstWindow,
+                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2));
+        final AccessibilityWindow secondWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(1);
+        setRegionForMockAccessibilityWindow(secondWindow,
+                new Region(0, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT));
+
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
 
         final List<AccessibilityWindowInfo> a11yWindows =
                 mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, hasSize(2));
         final Region outBounds = new Region();
         int windowId = a11yWindows.get(0).getId();
 
@@ -523,12 +647,17 @@
     @Test
     public void computePartialInteractiveRegionForWindow_halfVisible_returnHalfRegion() {
         // Updates z-order #1 WindowInfo is half visible.
-        WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
-        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
+        final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+        setRegionForMockAccessibilityWindow(firstWindow,
+                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2));
+        final AccessibilityWindow secondWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(1);
+        setRegionForMockAccessibilityWindow(secondWindow,
+                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
 
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
         final List<AccessibilityWindowInfo> a11yWindows =
                 mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, hasSize(2));
         final Region outBounds = new Region();
         int windowId = a11yWindows.get(1).getId();
 
@@ -539,9 +668,17 @@
 
     @Test
     public void computePartialInteractiveRegionForWindow_notVisible_returnEmptyRegion() {
-        // Since z-order #0 WindowInfo is full screen, z-order #1 WindowInfo should be invisible.
+        // z-order #0 WindowInfo is full screen, z-order #1 WindowInfo should be invisible.
+        final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+        setRegionForMockAccessibilityWindow(firstWindow,
+                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
         final List<AccessibilityWindowInfo> a11yWindows =
                 mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        // Note that the second window is also exposed even if region is empty because it's focused.
+        assertThat(a11yWindows, hasSize(2));
         final Region outBounds = new Region();
         int windowId = a11yWindows.get(1).getId();
 
@@ -552,16 +689,21 @@
     @Test
     public void computePartialInteractiveRegionForWindow_partialVisible_returnVisibleRegion() {
         // Updates z-order #0 WindowInfo to have two interact-able areas.
-        Region region = new Region(0, 0, SCREEN_WIDTH, 200);
+        final Region region = new Region(0, 0, SCREEN_WIDTH, 200);
         region.op(0, SCREEN_HEIGHT - 200, SCREEN_WIDTH, SCREEN_HEIGHT, Region.Op.UNION);
-        WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
-        windowInfo.regionInScreen.set(region);
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+        setRegionForMockAccessibilityWindow(firstWindow, region);
+        final AccessibilityWindow secondWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(1);
+        setRegionForMockAccessibilityWindow(secondWindow,
+                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
 
         final List<AccessibilityWindowInfo> a11yWindows =
                 mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, hasSize(2));
         final Region outBounds = new Region();
-        int windowId = a11yWindows.get(1).getId();
+        final int windowId = a11yWindows.get(1).getId();
 
         mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
         assertFalse(outBounds.getBounds().isEmpty());
@@ -572,7 +714,8 @@
     @Test
     public void updateActiveAndA11yFocusedWindow_windowStateChangedEvent_noTracking_shouldUpdate() {
         final IBinder eventWindowToken =
-                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1).token;
+                mWindows.get(Display.DEFAULT_DISPLAY)
+                        .get(DEFAULT_FOCUSED_INDEX + 1).getWindowInfo().token;
         final int eventWindowId = mA11yWindowManager.findWindowIdLocked(
                 USER_SYSTEM_ID, eventWindowToken);
         when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates())
@@ -611,11 +754,11 @@
                 .sendAccessibilityEventForCurrentUserLocked(captor.capture());
         assertThat(captor.getAllValues().get(0),
                 allOf(displayId(Display.DEFAULT_DISPLAY),
-                        a11yWindowId(currentActiveWindowId),
+                        eventWindowId(currentActiveWindowId),
                         a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
         assertThat(captor.getAllValues().get(1),
                 allOf(displayId(Display.DEFAULT_DISPLAY),
-                        a11yWindowId(eventWindowId),
+                        eventWindowId(eventWindowId),
                         a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
     }
 
@@ -641,7 +784,7 @@
                 .sendAccessibilityEventForCurrentUserLocked(captor.capture());
         assertThat(captor.getAllValues().get(0),
                 allOf(displayId(Display.DEFAULT_DISPLAY),
-                        a11yWindowId(eventWindowId),
+                        eventWindowId(eventWindowId),
                         a11yWindowChanges(
                                 AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
     }
@@ -690,12 +833,12 @@
                 .sendAccessibilityEventForCurrentUserLocked(captor.capture());
         assertThat(captor.getAllValues().get(0),
                 allOf(displayId(initialDisplayId),
-                        a11yWindowId(initialWindowId),
+                        eventWindowId(initialWindowId),
                         a11yWindowChanges(
                                 AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
         assertThat(captor.getAllValues().get(1),
                 allOf(displayId(eventDisplayId),
-                        a11yWindowId(eventWindowId),
+                        eventWindowId(eventWindowId),
                         a11yWindowChanges(
                                 AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
     }
@@ -722,7 +865,7 @@
                 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED,
                 noUse);
         assertThat(mA11yWindowManager.getFocusedWindowId(
-                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY),
+                        AccessibilityNodeInfo.FOCUS_ACCESSIBILITY),
                 is(AccessibilityWindowInfo.UNDEFINED_WINDOW_ID));
     }
 
@@ -751,11 +894,11 @@
                 .sendAccessibilityEventForCurrentUserLocked(captor.capture());
         assertThat(captor.getAllValues().get(0),
                 allOf(displayId(Display.DEFAULT_DISPLAY),
-                        a11yWindowId(eventWindowId),
+                        eventWindowId(eventWindowId),
                         a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
         assertThat(captor.getAllValues().get(1),
                 allOf(displayId(Display.DEFAULT_DISPLAY),
-                        a11yWindowId(currentActiveWindowId),
+                        eventWindowId(currentActiveWindowId),
                         a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
     }
 
@@ -763,7 +906,8 @@
     public void onTouchInteractionEnd_noServiceInteractiveWindow_shouldClearA11yFocus()
             throws RemoteException {
         final IBinder defaultFocusWinToken =
-                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).token;
+                mWindows.get(Display.DEFAULT_DISPLAY).get(
+                        DEFAULT_FOCUSED_INDEX).getWindowInfo().token;
         final int defaultFocusWindowId = mA11yWindowManager.findWindowIdLocked(
                 USER_SYSTEM_ID, defaultFocusWinToken);
         when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates())
@@ -808,8 +952,8 @@
     @Test
     public void getPictureInPictureWindow_shouldNotNull() {
         assertNull(mA11yWindowManager.getPictureInPictureWindowLocked());
-        mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1).inPictureInPicture = true;
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        mWindows.get(Display.DEFAULT_DISPLAY).get(1).getWindowInfo().inPictureInPicture = true;
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
 
         assertNotNull(mA11yWindowManager.getPictureInPictureWindowLocked());
     }
@@ -823,8 +967,9 @@
         final IAccessibilityInteractionConnection mockRemoteConnection =
                 mA11yWindowManager.getConnectionLocked(
                         USER_SYSTEM_ID, outsideWindowId).getRemote();
-        mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0).hasFlagWatchOutsideTouch = true;
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        mWindows.get(Display.DEFAULT_DISPLAY).get(0).getWindowInfo().hasFlagWatchOutsideTouch =
+                true;
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
 
         mA11yWindowManager.notifyOutsideTouch(USER_SYSTEM_ID, targetWindowId);
         verify(mockRemoteConnection).notifyOutsideTouch();
@@ -942,18 +1087,14 @@
 
     @Test
     public void sendAccessibilityEventOnWindowRemoval() {
-        final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
+        final ArrayList<AccessibilityWindow> windows = mWindows.get(Display.DEFAULT_DISPLAY);
 
         // Removing index 0 because it's not focused, and avoids unnecessary layer change.
         final int windowId =
                 getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
-        infos.remove(0);
-        for (WindowInfo info : infos) {
-            // Adjust layer number because it should start from 0.
-            info.layer--;
-        }
+        windows.remove(0);
 
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
 
         final ArgumentCaptor<AccessibilityEvent> captor =
                 ArgumentCaptor.forClass(AccessibilityEvent.class);
@@ -961,27 +1102,21 @@
                 .sendAccessibilityEventForCurrentUserLocked(captor.capture());
         assertThat(captor.getAllValues().get(0),
                 allOf(displayId(Display.DEFAULT_DISPLAY),
-                        a11yWindowId(windowId),
+                        eventWindowId(windowId),
                         a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_REMOVED)));
     }
 
     @Test
     public void sendAccessibilityEventOnWindowAddition() throws RemoteException {
-        final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
-
-        for (WindowInfo info : infos) {
-            // Adjust layer number because new window will have 0 so that layer number in
-            // A11yWindowInfo in window won't be changed.
-            info.layer++;
-        }
+        final ArrayList<AccessibilityWindow> windows = mWindows.get(Display.DEFAULT_DISPLAY);
 
         final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
                 false, USER_SYSTEM_ID);
-        addWindowInfo(infos, token, 0);
-        final int windowId =
-                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, infos.size() - 1);
+        // Adding window to the front so that other windows' layer won't change.
+        windows.add(0, createMockAccessibilityWindow(token, Display.DEFAULT_DISPLAY));
+        final int windowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
 
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
 
         final ArgumentCaptor<AccessibilityEvent> captor =
                 ArgumentCaptor.forClass(AccessibilityEvent.class);
@@ -989,17 +1124,17 @@
                 .sendAccessibilityEventForCurrentUserLocked(captor.capture());
         assertThat(captor.getAllValues().get(0),
                 allOf(displayId(Display.DEFAULT_DISPLAY),
-                        a11yWindowId(windowId),
+                        eventWindowId(windowId),
                         a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ADDED)));
     }
 
     @Test
     public void sendAccessibilityEventOnWindowChange() {
-        final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
-        infos.get(0).title = "new title";
+        final ArrayList<AccessibilityWindow> windows = mWindows.get(Display.DEFAULT_DISPLAY);
+        windows.get(0).getWindowInfo().title = "new title";
         final int windowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
 
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
 
         final ArgumentCaptor<AccessibilityEvent> captor =
                 ArgumentCaptor.forClass(AccessibilityEvent.class);
@@ -1007,7 +1142,7 @@
                 .sendAccessibilityEventForCurrentUserLocked(captor.capture());
         assertThat(captor.getAllValues().get(0),
                 allOf(displayId(Display.DEFAULT_DISPLAY),
-                        a11yWindowId(windowId),
+                        eventWindowId(windowId),
                         a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_TITLE)));
     }
 
@@ -1017,48 +1152,47 @@
     }
 
     private void startTrackingPerDisplay(int displayId) throws RemoteException {
-        ArrayList<WindowInfo> windowInfosForDisplay = new ArrayList<>();
+        ArrayList<AccessibilityWindow> windowsForDisplay = new ArrayList<>();
         // Adds RemoteAccessibilityConnection into AccessibilityWindowManager, and copy
         // mock window token into mA11yWindowTokens. Also, preparing WindowInfo mWindowInfos
         // for the test.
-        int layer = 0;
         for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) {
             final IWindow token = addAccessibilityInteractionConnection(displayId,
                     true, USER_SYSTEM_ID);
-            addWindowInfo(windowInfosForDisplay, token, layer++);
+            windowsForDisplay.add(createMockAccessibilityWindow(token, displayId));
 
         }
         for (int i = 0; i < NUM_APP_WINDOWS; i++) {
             final IWindow token = addAccessibilityInteractionConnection(displayId,
                     false, USER_SYSTEM_ID);
-            addWindowInfo(windowInfosForDisplay, token, layer++);
+            windowsForDisplay.add(createMockAccessibilityWindow(token, displayId));
         }
         // Sets up current focused window of display.
         // Each display has its own current focused window if config_perDisplayFocusEnabled is true.
         // Otherwise only default display needs to current focused window.
         if (mSupportPerDisplayFocus || displayId == Display.DEFAULT_DISPLAY) {
-            windowInfosForDisplay.get(DEFAULT_FOCUSED_INDEX).focused = true;
+            windowsForDisplay.get(DEFAULT_FOCUSED_INDEX).getWindowInfo().focused = true;
         }
         // Turns on windows tracking, and update window info.
         mA11yWindowManager.startTrackingWindows(displayId, false);
         // Puts window lists into array.
-        mWindowInfos.put(displayId, windowInfosForDisplay);
+        mWindows.put(displayId, windowsForDisplay);
         // Sets the default display is the top focused display and
         // its current focused window is the top focused window.
         if (displayId == Display.DEFAULT_DISPLAY) {
             setTopFocusedWindowAndDisplay(displayId, DEFAULT_FOCUSED_INDEX);
         }
         // Invokes callback for sending window lists to A11y framework.
-        onWindowsForAccessibilityChanged(displayId, FORCE_SEND);
+        onAccessibilityWindowsChanged(displayId, FORCE_SEND);
 
         assertEquals(mA11yWindowManager.getWindowListLocked(displayId).size(),
-                windowInfosForDisplay.size());
+                windowsForDisplay.size());
     }
 
     private WindowsForAccessibilityCallback getWindowsForAccessibilityCallbacks(int displayId) {
         ArgumentCaptor<WindowsForAccessibilityCallback> windowsForAccessibilityCallbacksCaptor =
                 ArgumentCaptor.forClass(
-                        WindowManagerInternal.WindowsForAccessibilityCallback.class);
+                        WindowsForAccessibilityCallback.class);
         verify(mMockWindowManagerInternal)
                 .setWindowsForAccessibilityCallback(eq(displayId),
                         windowsForAccessibilityCallbacksCaptor.capture());
@@ -1106,36 +1240,28 @@
         return windowId;
     }
 
-    private void addWindowInfo(ArrayList<WindowInfo> windowInfos, IWindow windowToken, int layer) {
-        final WindowInfo windowInfo = WindowInfo.obtain();
-        windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
-        windowInfo.token = windowToken.asBinder();
-        windowInfo.layer = layer;
-        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
-        windowInfos.add(windowInfo);
-    }
-
     private int getWindowIdFromWindowInfosForDisplay(int displayId, int index) {
-        final IBinder windowToken = mWindowInfos.get(displayId).get(index).token;
+        final IBinder windowToken = mWindows.get(displayId).get(index).getWindowInfo().token;
         return mA11yWindowManager.findWindowIdLocked(
                 USER_SYSTEM_ID, windowToken);
     }
 
     private void setTopFocusedWindowAndDisplay(int displayId, int index) {
         // Sets the top focus window.
-        mTopFocusedWindowToken = mWindowInfos.get(displayId).get(index).token;
+        mTopFocusedWindowToken = mWindows.get(displayId).get(index).getWindowInfo().token;
         // Sets the top focused display.
         mTopFocusedDisplayId = displayId;
     }
 
-    private void onWindowsForAccessibilityChanged(int displayId, boolean forceSend) {
+    private void onAccessibilityWindowsChanged(int displayId, boolean forceSend) {
         WindowsForAccessibilityCallback callbacks = mCallbackOfWindows.get(displayId);
         if (callbacks == null) {
             callbacks = getWindowsForAccessibilityCallbacks(displayId);
             mCallbackOfWindows.put(displayId, callbacks);
         }
-        callbacks.onWindowsForAccessibilityChanged(forceSend, mTopFocusedDisplayId,
-                mTopFocusedWindowToken, mWindowInfos.get(displayId));
+        callbacks.onAccessibilityWindowsChanged(forceSend, mTopFocusedDisplayId,
+                mTopFocusedWindowToken, new Point(SCREEN_WIDTH, SCREEN_HEIGHT),
+                mWindows.get(displayId));
     }
 
     private void changeFocusedWindowOnDisplayPerDisplayFocusConfig(
@@ -1144,23 +1270,23 @@
         if (mSupportPerDisplayFocus) {
             // Gets the old focused window of display which wants to change focused window.
             WindowInfo focusedWindowInfo =
-                    mWindowInfos.get(changeFocusedDisplayId).get(oldFocusedWindowIndex);
+                    mWindows.get(changeFocusedDisplayId).get(oldFocusedWindowIndex).getWindowInfo();
             // Resets the focus of old focused window.
             focusedWindowInfo.focused = false;
             // Gets the new window of display which wants to change focused window.
             focusedWindowInfo =
-                    mWindowInfos.get(changeFocusedDisplayId).get(newFocusedWindowIndex);
+                    mWindows.get(changeFocusedDisplayId).get(newFocusedWindowIndex).getWindowInfo();
             // Sets the focus of new focused window.
             focusedWindowInfo.focused = true;
         } else {
             // Gets the window of display which wants to change focused window.
             WindowInfo focusedWindowInfo =
-                    mWindowInfos.get(changeFocusedDisplayId).get(newFocusedWindowIndex);
+                    mWindows.get(changeFocusedDisplayId).get(newFocusedWindowIndex).getWindowInfo();
             // Sets the focus of new focused window.
             focusedWindowInfo.focused = true;
             // Gets the old focused window of old top focused display.
             focusedWindowInfo =
-                    mWindowInfos.get(oldTopFocusedDisplayId).get(oldFocusedWindowIndex);
+                    mWindows.get(oldTopFocusedDisplayId).get(oldFocusedWindowIndex).getWindowInfo();
             // Resets the focus of old focused window.
             focusedWindowInfo.focused = false;
             // Changes the top focused display and window.
@@ -1168,6 +1294,39 @@
         }
     }
 
+    private AccessibilityWindow createMockAccessibilityWindow(IWindow windowToken, int displayId) {
+        final WindowInfo windowInfo = WindowInfo.obtain();
+        windowInfo.type = WindowManager.LayoutParams.TYPE_APPLICATION;
+        windowInfo.token = windowToken.asBinder();
+
+        final AccessibilityWindow window = Mockito.mock(AccessibilityWindow.class);
+        when(window.getWindowInfo()).thenReturn(windowInfo);
+        when(window.isFocused()).thenAnswer(invocation -> windowInfo.focused);
+        when(window.isTouchable()).thenReturn(true);
+        when(window.getType()).thenReturn(windowInfo.type);
+
+        setRegionForMockAccessibilityWindow(window, nextToucableRegion(displayId));
+        return window;
+    }
+
+    private void setRegionForMockAccessibilityWindow(AccessibilityWindow window, Region region) {
+        doAnswer(invocation -> {
+            ((Region) invocation.getArgument(0)).set(region);
+            return null;
+        }).when(window).getTouchableRegionInScreen(any(Region.class));
+        doAnswer(invocation -> {
+            ((Region) invocation.getArgument(0)).set(region);
+            return null;
+        }).when(window).getTouchableRegionInWindow(any(Region.class));
+    }
+
+    private Region nextToucableRegion(int displayId) {
+        final int topLeft = mNextRegionOffsets.get(displayId, 0);
+        final int bottomRight = topLeft + 100;
+        mNextRegionOffsets.put(displayId, topLeft + 10);
+        return new Region(topLeft, topLeft, bottomRight, bottomRight);
+    }
+
     @Nullable
     private static String toString(@Nullable CharSequence cs) {
         return cs == null ? null : cs.toString();
@@ -1196,16 +1355,16 @@
         }
     }
 
-    static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
+    static class EventWindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
         private int mWindowId;
 
-        WindowIdMatcher(int windowId) {
+        EventWindowIdMatcher(int windowId) {
             super();
             mWindowId = windowId;
         }
 
-        static WindowIdMatcher a11yWindowId(int windowId) {
-            return new WindowIdMatcher(windowId);
+        static EventWindowIdMatcher eventWindowId(int windowId) {
+            return new EventWindowIdMatcher(windowId);
         }
 
         @Override
@@ -1241,5 +1400,27 @@
             description.appendText("Matching to window changes " + mWindowChanges);
         }
     }
+
+    static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityWindowInfo> {
+        private final int mWindowId;
+
+        WindowIdMatcher(int windowId) {
+            super();
+            mWindowId = windowId;
+        }
+
+        static WindowIdMatcher windowId(int windowId) {
+            return new WindowIdMatcher(windowId);
+        }
+
+        @Override
+        protected boolean matchesSafely(AccessibilityWindowInfo window) {
+            return window.getId() == mWindowId;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("Matching to windowId " + mWindowId);
+        }
+    }
 }
-// LINT.ThenChange(/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java)
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java
deleted file mode 100644
index 1904145..0000000
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java
+++ /dev/null
@@ -1,1444 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.accessibility;
-
-import static com.android.server.accessibility.AbstractAccessibilityServiceConnection.DISPLAY_TYPE_DEFAULT;
-import static com.android.server.accessibility.AccessibilityWindowManagerWithAccessibilityWindowTest.DisplayIdMatcher.displayId;
-import static com.android.server.accessibility.AccessibilityWindowManagerWithAccessibilityWindowTest.WindowIdMatcher.windowId;
-import static com.android.server.accessibility.AccessibilityWindowManagerWithAccessibilityWindowTest.WindowChangesMatcher.a11yWindowChanges;
-import static com.android.server.accessibility.AccessibilityWindowManagerWithAccessibilityWindowTest.EventWindowIdMatcher.eventWindowId;
-
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.allOf;
-import static org.hamcrest.Matchers.hasItem;
-import static org.hamcrest.Matchers.hasSize;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.Nullable;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.os.IBinder;
-import android.os.LocaleList;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
-import android.util.SparseArray;
-import android.view.Display;
-import android.view.IWindow;
-import android.view.WindowInfo;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityWindowAttributes;
-import android.view.accessibility.AccessibilityWindowInfo;
-import android.view.accessibility.IAccessibilityInteractionConnection;
-
-import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
-import com.android.server.accessibility.test.MessageCapturingHandler;
-import com.android.server.wm.AccessibilityWindowsPopulator.AccessibilityWindow;
-import com.android.server.wm.WindowManagerInternal;
-import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
-
-import org.hamcrest.Description;
-import org.hamcrest.TypeSafeMatcher;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Tests for the AccessibilityWindowManager with Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2
- * TODO(b/322444245): Merge with AccessibilityWindowManagerTest
- *  after completing the flag migration.
- */
-@RequiresFlagsEnabled(Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2)
-public class AccessibilityWindowManagerWithAccessibilityWindowTest {
-    private static final String PACKAGE_NAME = "com.android.server.accessibility";
-    private static final boolean FORCE_SEND = true;
-    private static final boolean SEND_ON_WINDOW_CHANGES = false;
-    private static final int USER_SYSTEM_ID = UserHandle.USER_SYSTEM;
-    private static final int USER_PROFILE = 11;
-    private static final int USER_PROFILE_PARENT = 1;
-    private static final int SECONDARY_DISPLAY_ID = Display.DEFAULT_DISPLAY + 1;
-    private static final int NUM_GLOBAL_WINDOWS = 4;
-    private static final int NUM_APP_WINDOWS = 4;
-    private static final int NUM_OF_WINDOWS = (NUM_GLOBAL_WINDOWS + NUM_APP_WINDOWS);
-    private static final int DEFAULT_FOCUSED_INDEX = 1;
-    private static final int SCREEN_WIDTH = 1080;
-    private static final int SCREEN_HEIGHT = 1920;
-    private static final int INVALID_ID = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
-    private static final int HOST_WINDOW_ID = 10;
-    private static final int EMBEDDED_WINDOW_ID = 11;
-    private static final int OTHER_WINDOW_ID = 12;
-
-    private AccessibilityWindowManager mA11yWindowManager;
-    // Window manager will support multiple focused window if config_perDisplayFocusEnabled is true,
-    // i.e., each display would have its current focused window, and one of all focused windows
-    // would be top focused window. Otherwise, window manager only supports one focused window
-    // at all displays, and that focused window would be top focused window.
-    private boolean mSupportPerDisplayFocus = false;
-    private int mTopFocusedDisplayId = Display.INVALID_DISPLAY;
-    private IBinder mTopFocusedWindowToken = null;
-
-    // List of window token, mapping from windowId -> window token.
-    private final SparseArray<IWindow> mA11yWindowTokens = new SparseArray<>();
-    // List of window info lists, mapping from displayId -> a11y window lists.
-    private final SparseArray<ArrayList<AccessibilityWindow>> mWindows = new SparseArray<>();
-    // List of callback, mapping from displayId -> callback.
-    private final SparseArray<WindowsForAccessibilityCallback> mCallbackOfWindows =
-            new SparseArray<>();
-    // List of display ID.
-    private final ArrayList<Integer> mExpectedDisplayList = new ArrayList<>(Arrays.asList(
-            Display.DEFAULT_DISPLAY, SECONDARY_DISPLAY_ID));
-
-    private final MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
-
-    // This maps displayId -> next region offset.
-    // Touchable region must have un-occluded area so that it's exposed to a11y services.
-    // This offset can be used as left and top of new region so that top-left of each region are
-    // kept visible.
-    // It's expected to be incremented by some amount everytime the value is used.
-    private final SparseArray<Integer> mNextRegionOffsets = new SparseArray<>();
-
-    @Mock
-    private WindowManagerInternal mMockWindowManagerInternal;
-    @Mock
-    private AccessibilityWindowManager.AccessibilityEventSender mMockA11yEventSender;
-    @Mock
-    private AccessibilitySecurityPolicy mMockA11ySecurityPolicy;
-    @Mock
-    private AccessibilitySecurityPolicy.AccessibilityUserManager mMockA11yUserManager;
-    @Mock
-    private AccessibilityTraceManager mMockA11yTraceManager;
-
-    @Mock
-    private IBinder mMockHostToken;
-    @Mock
-    private IBinder mMockEmbeddedToken;
-    @Mock
-    private IBinder mMockInvalidToken;
-
-    @Rule
-    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-
-    @Before
-    public void setUp() throws RemoteException {
-        MockitoAnnotations.initMocks(this);
-        when(mMockA11yUserManager.getCurrentUserIdLocked()).thenReturn(USER_SYSTEM_ID);
-        when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
-                USER_PROFILE)).thenReturn(USER_PROFILE_PARENT);
-        when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
-                USER_SYSTEM_ID)).thenReturn(USER_SYSTEM_ID);
-        when(mMockA11ySecurityPolicy.resolveValidReportedPackageLocked(
-                anyString(), anyInt(), anyInt(), anyInt())).thenReturn(PACKAGE_NAME);
-
-        doAnswer((invocation) -> {
-            onAccessibilityWindowsChanged(invocation.getArgument(0), false);
-            return null;
-        }).when(mMockWindowManagerInternal).computeWindowsForAccessibility(anyInt());
-
-        mA11yWindowManager = new AccessibilityWindowManager(new Object(), mHandler,
-                mMockWindowManagerInternal,
-                mMockA11yEventSender,
-                mMockA11ySecurityPolicy,
-                mMockA11yUserManager,
-                mMockA11yTraceManager);
-        // Starts tracking window of default display and sets the default display
-        // as top focused display before each testing starts.
-        startTrackingPerDisplay(Display.DEFAULT_DISPLAY);
-
-        // AccessibilityEventSender is invoked during onAccessibilityWindowsChanged.
-        // Resets it for mockito verify of further test case.
-        Mockito.reset(mMockA11yEventSender);
-
-        registerLeashedTokenAndWindowId();
-    }
-
-    @After
-    public void tearDown() {
-        mHandler.removeAllMessages();
-    }
-
-    @Test
-    public void startTrackingWindows_shouldEnableWindowManagerCallback() {
-        // AccessibilityWindowManager#startTrackingWindows already invoked in setup.
-        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
-        final WindowsForAccessibilityCallback callbacks =
-                mCallbackOfWindows.get(Display.DEFAULT_DISPLAY);
-        verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(
-                eq(Display.DEFAULT_DISPLAY), eq(callbacks));
-    }
-
-    @Test
-    public void stopTrackingWindows_shouldDisableWindowManagerCallback() {
-        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
-        Mockito.reset(mMockWindowManagerInternal);
-
-        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
-        assertFalse(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
-        verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(
-                eq(Display.DEFAULT_DISPLAY), isNull());
-
-    }
-
-    @Test
-    public void stopTrackingWindows_shouldClearWindows() {
-        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
-        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
-
-        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
-        assertNull(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY));
-        assertEquals(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
-                AccessibilityWindowInfo.UNDEFINED_WINDOW_ID);
-        assertEquals(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID),
-                activeWindowId);
-    }
-
-    @Test
-    public void stopTrackingWindows_onNonTopFocusedDisplay_shouldNotResetTopFocusWindow()
-            throws RemoteException {
-        // At setup, the default display sets be the top focused display and
-        // its current focused window sets be the top focused window.
-        // Starts tracking window of second display.
-        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
-        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID));
-        // Stops tracking windows of second display.
-        mA11yWindowManager.stopTrackingWindows(SECONDARY_DISPLAY_ID);
-        assertNotEquals(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
-                AccessibilityWindowInfo.UNDEFINED_WINDOW_ID);
-    }
-
-    @Test
-    public void onWindowsChanged_duringTouchInteractAndFocusChange_shouldChangeActiveWindow() {
-        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
-        final WindowInfo focusedWindowInfo =
-                mWindows.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).getWindowInfo();
-        assertEquals(activeWindowId, mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, focusedWindowInfo.token));
-
-        focusedWindowInfo.focused = false;
-        mWindows.get(Display.DEFAULT_DISPLAY).get(
-                DEFAULT_FOCUSED_INDEX + 1).getWindowInfo().focused = true;
-
-        mA11yWindowManager.onTouchInteractionStart();
-        setTopFocusedWindowAndDisplay(Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX + 1);
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
-    }
-
-    @Test
-    public void
-            onWindowsChanged_focusChangeOnNonTopFocusedDisplay_perDisplayFocusOn_notChangeWindow()
-            throws RemoteException {
-        // At setup, the default display sets be the top focused display and
-        // its current focused window sets be the top focused window.
-        // Sets supporting multiple focused window, i.e., config_perDisplayFocusEnabled is true.
-        mSupportPerDisplayFocus = true;
-        // Starts tracking window of second display.
-        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
-        // Gets the active window.
-        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
-        // Gets the top focused window.
-        final int topFocusedWindowId =
-                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT);
-        // Changes the current focused window at second display.
-        changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID,
-                DEFAULT_FOCUSED_INDEX + 1, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX);
-
-        onAccessibilityWindowsChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
-        // The active window should not be changed.
-        assertEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
-        // The top focused window should not be changed.
-        assertEquals(topFocusedWindowId,
-                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT));
-    }
-
-    @Test
-    public void
-            onWindowChange_focusChangeToNonTopFocusedDisplay_perDisplayFocusOff_shouldChangeWindow()
-            throws RemoteException {
-        // At setup, the default display sets be the top focused display and
-        // its current focused window sets be the top focused window.
-        // Sets not supporting multiple focused window, i.e., config_perDisplayFocusEnabled is
-        // false.
-        mSupportPerDisplayFocus = false;
-        // Starts tracking window of second display.
-        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
-        // Gets the active window.
-        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
-        // Gets the top focused window.
-        final int topFocusedWindowId =
-                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT);
-        // Changes the current focused window from default display to second display.
-        changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID,
-                DEFAULT_FOCUSED_INDEX, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-        onAccessibilityWindowsChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
-        // The active window should be changed.
-        assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
-        // The top focused window should be changed.
-        assertNotEquals(topFocusedWindowId,
-                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT));
-    }
-
-    @Test
-    public void onWindowsChanged_shouldReportCorrectLayer() {
-        // AccessibilityWindowManager#onAccessibilityWindowsChanged already invoked in setup.
-        List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        for (int i = 0; i < a11yWindows.size(); i++) {
-            final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
-            assertThat(mWindows.get(Display.DEFAULT_DISPLAY).size() - i - 1,
-                    is(a11yWindow.getLayer()));
-        }
-    }
-
-    @Test
-    public void onWindowsChanged_shouldReportCorrectOrder() {
-        // AccessibilityWindowManager#onAccessibilityWindowsChanged already invoked in setup.
-        List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        for (int i = 0; i < a11yWindows.size(); i++) {
-            final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
-            final IBinder windowToken = mA11yWindowManager
-                    .getWindowTokenForUserAndWindowIdLocked(USER_SYSTEM_ID, a11yWindow.getId());
-            final WindowInfo windowInfo = mWindows.get(Display.DEFAULT_DISPLAY)
-                    .get(i).getWindowInfo();
-            assertThat(windowToken, is(windowInfo.token));
-        }
-    }
-
-    @Test
-    public void onWindowsChanged_shouldNotReportNonTouchableWindow() {
-        final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
-        when(window.isTouchable()).thenReturn(false);
-        final int windowId = mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, window.getWindowInfo().token);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, not(hasItem(windowId(windowId))));
-    }
-
-    @Test
-    public void onWindowsChanged_shouldReportFocusedNonTouchableWindow() {
-        final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(
-                DEFAULT_FOCUSED_INDEX);
-        when(window.isTouchable()).thenReturn(false);
-        final int windowId = mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, window.getWindowInfo().token);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, hasItem(windowId(windowId)));
-    }
-
-    @Test
-    public void onWindowsChanged_trustedFocusedNonTouchableWindow_shouldNotHideWindowsBelow() {
-        // Make the focused trusted un-touchable window fullscreen.
-        final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(
-                DEFAULT_FOCUSED_INDEX);
-        setRegionForMockAccessibilityWindow(window, new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
-        when(window.isTouchable()).thenReturn(false);
-        when(window.isTrustedOverlay()).thenReturn(true);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, hasSize(NUM_OF_WINDOWS));
-    }
-
-    @Test
-    public void onWindowsChanged_accessibilityOverlay_shouldNotHideWindowsBelow() {
-        // Make the a11y overlay window fullscreen.
-        final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
-        setRegionForMockAccessibilityWindow(window, new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
-        when(window.getType()).thenReturn(WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, hasSize(NUM_OF_WINDOWS));
-    }
-
-    @Test
-    public void onWindowsChanged_shouldReportFocusedWindowEvenIfOccluded() {
-        // Make the front window fullscreen.
-        final AccessibilityWindow frontWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
-        setRegionForMockAccessibilityWindow(frontWindow,
-                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
-        final int frontWindowId = mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, frontWindow.getWindowInfo().token);
-
-        final AccessibilityWindow focusedWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(
-                DEFAULT_FOCUSED_INDEX);
-        final int focusedWindowId = mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, focusedWindow.getWindowInfo().token);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, hasSize(2));
-        assertThat(a11yWindows.get(0), windowId(frontWindowId));
-        assertThat(a11yWindows.get(1), windowId(focusedWindowId));
-    }
-
-    @Test
-    public void onWindowsChanged_embeddedWindows_shouldOnlyReportHost() throws RemoteException {
-        final Rect embeddingBounds = new Rect(0, 0, 200, 100);
-
-        // The embedded window comes front of the host window.
-        final IBinder embeddedWindowLeashToken = Mockito.mock(IBinder.class);
-        final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                false, embeddedWindowLeashToken, USER_SYSTEM_ID);
-        final AccessibilityWindow embeddedWindow = createMockAccessibilityWindow(
-                mA11yWindowTokens.get(embeddedWindowId), Display.DEFAULT_DISPLAY);
-        setRegionForMockAccessibilityWindow(embeddedWindow, new Region(embeddingBounds));
-        mWindows.get(Display.DEFAULT_DISPLAY).set(0, embeddedWindow);
-
-        final IBinder hostWindowLeashToken = Mockito.mock(IBinder.class);
-        final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                false, hostWindowLeashToken, USER_SYSTEM_ID);
-        final AccessibilityWindow hostWindow = createMockAccessibilityWindow(
-                mA11yWindowTokens.get(hostWindowId), Display.DEFAULT_DISPLAY);
-        setRegionForMockAccessibilityWindow(hostWindow, new Region(embeddingBounds));
-        mWindows.get(Display.DEFAULT_DISPLAY).set(1, hostWindow);
-
-        mA11yWindowManager.associateEmbeddedHierarchyLocked(
-                hostWindowLeashToken, embeddedWindowLeashToken);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, not(hasItem(windowId(embeddedWindowId))));
-        assertThat(a11yWindows.get(0), windowId(hostWindowId));
-        final Rect bounds = new Rect();
-        a11yWindows.get(0).getBoundsInScreen(bounds);
-        assertEquals(bounds, embeddingBounds);
-    }
-
-    @Test
-    public void onWindowsChanged_shouldNotReportfullyOccludedWindow() {
-        final AccessibilityWindow frontWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
-        setRegionForMockAccessibilityWindow(frontWindow, new Region(100, 100, 300, 300));
-        final int frontWindowId = mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, frontWindow.getWindowInfo().token);
-
-        // index 1 is focused. Let's use the next one for this test.
-        final AccessibilityWindow occludedWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(2);
-        setRegionForMockAccessibilityWindow(occludedWindow, new Region(150, 150, 250, 250));
-        final int occludedWindowId = mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, occludedWindow.getWindowInfo().token);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, hasItem(windowId(frontWindowId)));
-        assertThat(a11yWindows, not(hasItem(windowId(occludedWindowId))));
-    }
-
-    @Test
-    public void onWindowsChangedAndForceSend_shouldUpdateWindows() {
-        assertNotEquals("new title",
-                toString(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)
-                        .get(0).getTitle()));
-
-        mWindows.get(Display.DEFAULT_DISPLAY).get(0).getWindowInfo().title = "new title";
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
-        assertEquals("new title",
-                toString(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)
-                        .get(0).getTitle()));
-    }
-
-    @Test
-    public void onWindowsChangedNoForceSend_windowChanged_shouldUpdateWindows()
-            throws RemoteException {
-        final AccessibilityWindowInfo oldWindow =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0);
-        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                true, USER_SYSTEM_ID);
-        mWindows.get(Display.DEFAULT_DISPLAY).set(0,
-                createMockAccessibilityWindow(token, Display.DEFAULT_DISPLAY));
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-        assertNotEquals(oldWindow,
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0));
-    }
-
-    @Test
-    public void onWindowsChangedNoForceSend_focusChanged_shouldUpdateWindows() {
-        final WindowInfo focusedWindowInfo =
-                mWindows.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).getWindowInfo();
-        final WindowInfo windowInfo = mWindows.get(Display.DEFAULT_DISPLAY).get(0).getWindowInfo();
-        focusedWindowInfo.focused = false;
-        windowInfo.focused = true;
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-        assertTrue(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0)
-                .isFocused());
-    }
-
-    @Test
-    public void removeAccessibilityInteractionConnection_byWindowToken_shouldRemoved() {
-        for (int i = 0; i < NUM_OF_WINDOWS; i++) {
-            final int windowId = mA11yWindowTokens.keyAt(i);
-            final IWindow windowToken = mA11yWindowTokens.valueAt(i);
-            assertNotNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId));
-
-            mA11yWindowManager.removeAccessibilityInteractionConnection(windowToken);
-            assertNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId));
-        }
-    }
-
-    @Test
-    public void remoteAccessibilityConnection_binderDied_shouldRemoveConnection() {
-        for (int i = 0; i < NUM_OF_WINDOWS; i++) {
-            final int windowId = mA11yWindowTokens.keyAt(i);
-            final RemoteAccessibilityConnection remoteA11yConnection =
-                    mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId);
-            assertNotNull(remoteA11yConnection);
-
-            remoteA11yConnection.binderDied();
-            assertNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId));
-        }
-    }
-
-    @Test
-    public void getWindowTokenForUserAndWindowId_shouldNotNull() {
-        final List<AccessibilityWindowInfo> windows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        for (int i = 0; i < windows.size(); i++) {
-            final int windowId = windows.get(i).getId();
-
-            assertNotNull(mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
-                    USER_SYSTEM_ID, windowId));
-        }
-    }
-
-    @Test
-    public void findWindowId() {
-        final List<AccessibilityWindowInfo> windows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        for (int i = 0; i < windows.size(); i++) {
-            final int windowId = windows.get(i).getId();
-            final IBinder windowToken = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
-                    USER_SYSTEM_ID, windowId);
-
-            assertEquals(mA11yWindowManager.findWindowIdLocked(
-                    USER_SYSTEM_ID, windowToken), windowId);
-        }
-    }
-
-    @Test
-    public void resolveParentWindowId_windowIsNotEmbedded_shouldReturnGivenId()
-            throws RemoteException {
-        final int windowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, false,
-                Mockito.mock(IBinder.class), USER_SYSTEM_ID);
-        assertEquals(windowId, mA11yWindowManager.resolveParentWindowIdLocked(windowId));
-    }
-
-    @Test
-    public void resolveParentWindowId_windowIsNotRegistered_shouldReturnGivenId() {
-        final int windowId = -1;
-        assertEquals(windowId, mA11yWindowManager.resolveParentWindowIdLocked(windowId));
-    }
-
-    @Test
-    public void resolveParentWindowId_windowIsAssociated_shouldReturnParentWindowId()
-            throws RemoteException {
-        final IBinder mockHostToken = Mockito.mock(IBinder.class);
-        final IBinder mockEmbeddedToken = Mockito.mock(IBinder.class);
-        final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                false, mockHostToken, USER_SYSTEM_ID);
-        final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                false, mockEmbeddedToken, USER_SYSTEM_ID);
-
-        mA11yWindowManager.associateEmbeddedHierarchyLocked(mockHostToken, mockEmbeddedToken);
-
-        final int resolvedWindowId = mA11yWindowManager.resolveParentWindowIdLocked(
-                embeddedWindowId);
-        assertEquals(hostWindowId, resolvedWindowId);
-    }
-
-    @Test
-    public void resolveParentWindowId_windowIsDisassociated_shouldReturnGivenId()
-            throws RemoteException {
-        final IBinder mockHostToken = Mockito.mock(IBinder.class);
-        final IBinder mockEmbeddedToken = Mockito.mock(IBinder.class);
-        final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                false, mockHostToken, USER_SYSTEM_ID);
-        final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                false, mockEmbeddedToken, USER_SYSTEM_ID);
-
-        mA11yWindowManager.associateEmbeddedHierarchyLocked(mockHostToken, mockEmbeddedToken);
-        mA11yWindowManager.disassociateEmbeddedHierarchyLocked(mockEmbeddedToken);
-
-        final int resolvedWindowId = mA11yWindowManager.resolveParentWindowIdLocked(
-                embeddedWindowId);
-        assertNotEquals(hostWindowId, resolvedWindowId);
-        assertEquals(embeddedWindowId, resolvedWindowId);
-    }
-
-    @Test
-    public void computePartialInteractiveRegionForWindow_wholeVisible_returnWholeRegion() {
-        // Updates top 2 z-order WindowInfo are whole visible.
-        final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
-        setRegionForMockAccessibilityWindow(firstWindow,
-                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2));
-        final AccessibilityWindow secondWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(1);
-        setRegionForMockAccessibilityWindow(secondWindow,
-                new Region(0, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT));
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, hasSize(2));
-        final Region outBounds = new Region();
-        int windowId = a11yWindows.get(0).getId();
-
-        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
-        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
-        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
-
-        windowId = a11yWindows.get(1).getId();
-
-        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
-        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
-        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
-    }
-
-    @Test
-    public void computePartialInteractiveRegionForWindow_halfVisible_returnHalfRegion() {
-        // Updates z-order #1 WindowInfo is half visible.
-        final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
-        setRegionForMockAccessibilityWindow(firstWindow,
-                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2));
-        final AccessibilityWindow secondWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(1);
-        setRegionForMockAccessibilityWindow(secondWindow,
-                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, hasSize(2));
-        final Region outBounds = new Region();
-        int windowId = a11yWindows.get(1).getId();
-
-        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
-        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
-        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
-    }
-
-    @Test
-    public void computePartialInteractiveRegionForWindow_notVisible_returnEmptyRegion() {
-        // z-order #0 WindowInfo is full screen, z-order #1 WindowInfo should be invisible.
-        final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
-        setRegionForMockAccessibilityWindow(firstWindow,
-                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        // Note that the second window is also exposed even if region is empty because it's focused.
-        assertThat(a11yWindows, hasSize(2));
-        final Region outBounds = new Region();
-        int windowId = a11yWindows.get(1).getId();
-
-        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
-        assertTrue(outBounds.getBounds().isEmpty());
-    }
-
-    @Test
-    public void computePartialInteractiveRegionForWindow_partialVisible_returnVisibleRegion() {
-        // Updates z-order #0 WindowInfo to have two interact-able areas.
-        final Region region = new Region(0, 0, SCREEN_WIDTH, 200);
-        region.op(0, SCREEN_HEIGHT - 200, SCREEN_WIDTH, SCREEN_HEIGHT, Region.Op.UNION);
-        final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
-        setRegionForMockAccessibilityWindow(firstWindow, region);
-        final AccessibilityWindow secondWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(1);
-        setRegionForMockAccessibilityWindow(secondWindow,
-                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, hasSize(2));
-        final Region outBounds = new Region();
-        final int windowId = a11yWindows.get(1).getId();
-
-        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
-        assertFalse(outBounds.getBounds().isEmpty());
-        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
-        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT - 400));
-    }
-
-    @Test
-    public void updateActiveAndA11yFocusedWindow_windowStateChangedEvent_noTracking_shouldUpdate() {
-        final IBinder eventWindowToken =
-                mWindows.get(Display.DEFAULT_DISPLAY)
-                        .get(DEFAULT_FOCUSED_INDEX + 1).getWindowInfo().token;
-        final int eventWindowId = mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, eventWindowToken);
-        when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates())
-                .thenReturn(eventWindowToken);
-
-        final int noUse = 0;
-        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                eventWindowId,
-                noUse,
-                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
-                noUse);
-        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId));
-        assertThat(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
-                is(eventWindowId));
-    }
-
-    @Test
-    public void updateActiveAndA11yFocusedWindow_hoverEvent_touchInteract_shouldSetActiveWindow() {
-        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
-                DEFAULT_FOCUSED_INDEX + 1);
-        final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
-        assertThat(currentActiveWindowId, is(not(eventWindowId)));
-
-        final int noUse = 0;
-        mA11yWindowManager.onTouchInteractionStart();
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                eventWindowId,
-                noUse,
-                AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
-                noUse);
-        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId));
-        final ArgumentCaptor<AccessibilityEvent> captor =
-                ArgumentCaptor.forClass(AccessibilityEvent.class);
-        verify(mMockA11yEventSender, times(2))
-                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
-        assertThat(captor.getAllValues().get(0),
-                allOf(displayId(Display.DEFAULT_DISPLAY),
-                        eventWindowId(currentActiveWindowId),
-                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
-        assertThat(captor.getAllValues().get(1),
-                allOf(displayId(Display.DEFAULT_DISPLAY),
-                        eventWindowId(eventWindowId),
-                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
-    }
-
-    @Test
-    public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_shouldUpdateA11yFocus() {
-        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
-                DEFAULT_FOCUSED_INDEX);
-        final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId(
-                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
-        assertThat(currentA11yFocusedWindowId, is(AccessibilityWindowInfo.UNDEFINED_WINDOW_ID));
-
-        final int noUse = 0;
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                eventWindowId,
-                AccessibilityNodeInfo.ROOT_NODE_ID,
-                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
-                noUse);
-        assertThat(mA11yWindowManager.getFocusedWindowId(
-                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
-        final ArgumentCaptor<AccessibilityEvent> captor =
-                ArgumentCaptor.forClass(AccessibilityEvent.class);
-        verify(mMockA11yEventSender, times(1))
-                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
-        assertThat(captor.getAllValues().get(0),
-                allOf(displayId(Display.DEFAULT_DISPLAY),
-                        eventWindowId(eventWindowId),
-                        a11yWindowChanges(
-                                AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
-    }
-
-    @Test
-    public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_multiDisplay_defaultToSecondary()
-            throws RemoteException {
-        runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
-                Display.DEFAULT_DISPLAY, SECONDARY_DISPLAY_ID);
-    }
-
-    @Test
-    public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_multiDisplay_SecondaryToDefault()
-            throws RemoteException {
-        runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
-                SECONDARY_DISPLAY_ID, Display.DEFAULT_DISPLAY);
-    }
-
-    private void runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
-            int initialDisplayId, int eventDisplayId) throws RemoteException {
-        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
-        final int initialWindowId = getWindowIdFromWindowInfosForDisplay(
-                initialDisplayId, DEFAULT_FOCUSED_INDEX);
-        final int noUse = 0;
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                initialWindowId,
-                AccessibilityNodeInfo.ROOT_NODE_ID,
-                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
-                noUse);
-        assertThat(mA11yWindowManager.getFocusedWindowId(
-                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(initialWindowId));
-        Mockito.reset(mMockA11yEventSender);
-
-        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(
-                eventDisplayId, DEFAULT_FOCUSED_INDEX);
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                eventWindowId,
-                AccessibilityNodeInfo.ROOT_NODE_ID,
-                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
-                noUse);
-        assertThat(mA11yWindowManager.getFocusedWindowId(
-                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
-        final ArgumentCaptor<AccessibilityEvent> captor =
-                ArgumentCaptor.forClass(AccessibilityEvent.class);
-        verify(mMockA11yEventSender, times(2))
-                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
-        assertThat(captor.getAllValues().get(0),
-                allOf(displayId(initialDisplayId),
-                        eventWindowId(initialWindowId),
-                        a11yWindowChanges(
-                                AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
-        assertThat(captor.getAllValues().get(1),
-                allOf(displayId(eventDisplayId),
-                        eventWindowId(eventWindowId),
-                        a11yWindowChanges(
-                                AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
-    }
-
-    @Test
-    public void updateActiveAndA11yFocusedWindow_clearA11yFocusEvent_shouldClearA11yFocus() {
-        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
-                DEFAULT_FOCUSED_INDEX);
-        final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId(
-                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
-        assertThat(currentA11yFocusedWindowId, is(not(eventWindowId)));
-
-        final int noUse = 0;
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                eventWindowId,
-                AccessibilityNodeInfo.ROOT_NODE_ID,
-                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
-                noUse);
-        assertThat(mA11yWindowManager.getFocusedWindowId(
-                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                eventWindowId,
-                AccessibilityNodeInfo.ROOT_NODE_ID,
-                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED,
-                noUse);
-        assertThat(mA11yWindowManager.getFocusedWindowId(
-                        AccessibilityNodeInfo.FOCUS_ACCESSIBILITY),
-                is(AccessibilityWindowInfo.UNDEFINED_WINDOW_ID));
-    }
-
-    @Test
-    public void onTouchInteractionEnd_shouldRollbackActiveWindow() {
-        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
-                DEFAULT_FOCUSED_INDEX + 1);
-        final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
-        assertThat(currentActiveWindowId, is(not(eventWindowId)));
-
-        final int noUse = 0;
-        mA11yWindowManager.onTouchInteractionStart();
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                eventWindowId,
-                noUse,
-                AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
-                noUse);
-        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId));
-        // AccessibilityEventSender is invoked after active window changed. Reset it.
-        Mockito.reset(mMockA11yEventSender);
-
-        mA11yWindowManager.onTouchInteractionEnd();
-        final ArgumentCaptor<AccessibilityEvent> captor =
-                ArgumentCaptor.forClass(AccessibilityEvent.class);
-        verify(mMockA11yEventSender, times(2))
-                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
-        assertThat(captor.getAllValues().get(0),
-                allOf(displayId(Display.DEFAULT_DISPLAY),
-                        eventWindowId(eventWindowId),
-                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
-        assertThat(captor.getAllValues().get(1),
-                allOf(displayId(Display.DEFAULT_DISPLAY),
-                        eventWindowId(currentActiveWindowId),
-                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
-    }
-
-    @Test
-    public void onTouchInteractionEnd_noServiceInteractiveWindow_shouldClearA11yFocus()
-            throws RemoteException {
-        final IBinder defaultFocusWinToken =
-                mWindows.get(Display.DEFAULT_DISPLAY).get(
-                        DEFAULT_FOCUSED_INDEX).getWindowInfo().token;
-        final int defaultFocusWindowId = mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, defaultFocusWinToken);
-        when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates())
-                .thenReturn(defaultFocusWinToken);
-        final int newFocusWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
-                DEFAULT_FOCUSED_INDEX + 1);
-        final IAccessibilityInteractionConnection mockNewFocusConnection =
-                mA11yWindowManager.getConnectionLocked(
-                        USER_SYSTEM_ID, newFocusWindowId).getRemote();
-
-        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
-        final int noUse = 0;
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                defaultFocusWindowId,
-                noUse,
-                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
-                noUse);
-        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(defaultFocusWindowId));
-        assertThat(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
-                is(defaultFocusWindowId));
-
-        mA11yWindowManager.onTouchInteractionStart();
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                newFocusWindowId,
-                noUse,
-                AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
-                noUse);
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                newFocusWindowId,
-                AccessibilityNodeInfo.ROOT_NODE_ID,
-                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
-                noUse);
-        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(newFocusWindowId));
-        assertThat(mA11yWindowManager.getFocusedWindowId(
-                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(newFocusWindowId));
-
-        mA11yWindowManager.onTouchInteractionEnd();
-        mHandler.sendLastMessage();
-        verify(mockNewFocusConnection).clearAccessibilityFocus();
-    }
-
-    @Test
-    public void getPictureInPictureWindow_shouldNotNull() {
-        assertNull(mA11yWindowManager.getPictureInPictureWindowLocked());
-        mWindows.get(Display.DEFAULT_DISPLAY).get(1).getWindowInfo().inPictureInPicture = true;
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        assertNotNull(mA11yWindowManager.getPictureInPictureWindowLocked());
-    }
-
-    @Test
-    public void notifyOutsideTouch() throws RemoteException {
-        final int targetWindowId =
-                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 1);
-        final int outsideWindowId =
-                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
-        final IAccessibilityInteractionConnection mockRemoteConnection =
-                mA11yWindowManager.getConnectionLocked(
-                        USER_SYSTEM_ID, outsideWindowId).getRemote();
-        mWindows.get(Display.DEFAULT_DISPLAY).get(0).getWindowInfo().hasFlagWatchOutsideTouch =
-                true;
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        mA11yWindowManager.notifyOutsideTouch(USER_SYSTEM_ID, targetWindowId);
-        verify(mockRemoteConnection).notifyOutsideTouch();
-    }
-
-    @Test
-    public void addAccessibilityInteractionConnection_profileUser_findInParentUser()
-            throws RemoteException {
-        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                false, USER_PROFILE);
-        final int windowId = mA11yWindowManager.findWindowIdLocked(
-                USER_PROFILE_PARENT, token.asBinder());
-        assertTrue(windowId >= 0);
-    }
-
-    @Test
-    public void getDisplayList() throws RemoteException {
-        // Starts tracking window of second display.
-        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
-
-        final ArrayList<Integer> displayList = mA11yWindowManager.getDisplayListLocked(
-                DISPLAY_TYPE_DEFAULT);
-        assertTrue(displayList.equals(mExpectedDisplayList));
-    }
-
-    @Test
-    public void setAccessibilityWindowIdToSurfaceMetadata()
-            throws RemoteException {
-        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                true, USER_SYSTEM_ID);
-        int windowId = -1;
-        for (int i = 0; i < mA11yWindowTokens.size(); i++) {
-            if (mA11yWindowTokens.valueAt(i).equals(token)) {
-                windowId = mA11yWindowTokens.keyAt(i);
-            }
-        }
-        assertNotEquals("Returned token is not found in mA11yWindowTokens", -1, windowId);
-        verify(mMockWindowManagerInternal, times(1)).setAccessibilityIdToSurfaceMetadata(
-                token.asBinder(), windowId);
-
-        mA11yWindowManager.removeAccessibilityInteractionConnection(token);
-        verify(mMockWindowManagerInternal, times(1)).setAccessibilityIdToSurfaceMetadata(
-                token.asBinder(), -1);
-    }
-
-    @Test
-    public void getHostTokenLocked_hierarchiesAreAssociated_shouldReturnHostToken() {
-        mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken);
-        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken);
-        assertEquals(hostToken, mMockHostToken);
-    }
-
-    @Test
-    public void getHostTokenLocked_hierarchiesAreNotAssociated_shouldReturnNull() {
-        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken);
-        assertNull(hostToken);
-    }
-
-    @Test
-    public void getHostTokenLocked_embeddedHierarchiesAreDisassociated_shouldReturnNull() {
-        mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken);
-        mA11yWindowManager.disassociateLocked(mMockEmbeddedToken);
-        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken);
-        assertNull(hostToken);
-    }
-
-    @Test
-    public void getHostTokenLocked_hostHierarchiesAreDisassociated_shouldReturnNull() {
-        mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken);
-        mA11yWindowManager.disassociateLocked(mMockHostToken);
-        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockHostToken);
-        assertNull(hostToken);
-    }
-
-    @Test
-    public void getWindowIdLocked_windowIsRegistered_shouldReturnWindowId() {
-        final int windowId = mA11yWindowManager.getWindowIdLocked(mMockHostToken);
-        assertEquals(windowId, HOST_WINDOW_ID);
-    }
-
-    @Test
-    public void getWindowIdLocked_windowIsNotRegistered_shouldReturnInvalidWindowId() {
-        final int windowId = mA11yWindowManager.getWindowIdLocked(mMockInvalidToken);
-        assertEquals(windowId, INVALID_ID);
-    }
-
-    @Test
-    public void getTokenLocked_windowIsRegistered_shouldReturnToken() {
-        final IBinder token = mA11yWindowManager.getLeashTokenLocked(HOST_WINDOW_ID);
-        assertEquals(token, mMockHostToken);
-    }
-
-    @Test
-    public void getTokenLocked_windowIsNotRegistered_shouldReturnNull() {
-        final IBinder token = mA11yWindowManager.getLeashTokenLocked(OTHER_WINDOW_ID);
-        assertNull(token);
-    }
-
-    @Test
-    public void setAccessibilityWindowAttributes_windowIsNotRegistered_titleIsChanged() {
-        final int windowId =
-                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
-        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
-        layoutParams.accessibilityTitle = "accessibility window title";
-        final AccessibilityWindowAttributes attributes = new AccessibilityWindowAttributes(
-                layoutParams, new LocaleList());
-
-        mA11yWindowManager.setAccessibilityWindowAttributes(Display.DEFAULT_DISPLAY, windowId,
-                USER_SYSTEM_ID, attributes);
-
-        final AccessibilityWindowInfo a11yWindow = mA11yWindowManager.findA11yWindowInfoByIdLocked(
-                windowId);
-        assertEquals(toString(layoutParams.accessibilityTitle), toString(a11yWindow.getTitle()));
-    }
-
-    @Test
-    public void sendAccessibilityEventOnWindowRemoval() {
-        final ArrayList<AccessibilityWindow> windows = mWindows.get(Display.DEFAULT_DISPLAY);
-
-        // Removing index 0 because it's not focused, and avoids unnecessary layer change.
-        final int windowId =
-                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
-        windows.remove(0);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
-
-        final ArgumentCaptor<AccessibilityEvent> captor =
-                ArgumentCaptor.forClass(AccessibilityEvent.class);
-        verify(mMockA11yEventSender, times(1))
-                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
-        assertThat(captor.getAllValues().get(0),
-                allOf(displayId(Display.DEFAULT_DISPLAY),
-                        eventWindowId(windowId),
-                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_REMOVED)));
-    }
-
-    @Test
-    public void sendAccessibilityEventOnWindowAddition() throws RemoteException {
-        final ArrayList<AccessibilityWindow> windows = mWindows.get(Display.DEFAULT_DISPLAY);
-
-        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                false, USER_SYSTEM_ID);
-        // Adding window to the front so that other windows' layer won't change.
-        windows.add(0, createMockAccessibilityWindow(token, Display.DEFAULT_DISPLAY));
-        final int windowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
-
-        final ArgumentCaptor<AccessibilityEvent> captor =
-                ArgumentCaptor.forClass(AccessibilityEvent.class);
-        verify(mMockA11yEventSender, times(1))
-                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
-        assertThat(captor.getAllValues().get(0),
-                allOf(displayId(Display.DEFAULT_DISPLAY),
-                        eventWindowId(windowId),
-                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ADDED)));
-    }
-
-    @Test
-    public void sendAccessibilityEventOnWindowChange() {
-        final ArrayList<AccessibilityWindow> windows = mWindows.get(Display.DEFAULT_DISPLAY);
-        windows.get(0).getWindowInfo().title = "new title";
-        final int windowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
-
-        final ArgumentCaptor<AccessibilityEvent> captor =
-                ArgumentCaptor.forClass(AccessibilityEvent.class);
-        verify(mMockA11yEventSender, times(1))
-                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
-        assertThat(captor.getAllValues().get(0),
-                allOf(displayId(Display.DEFAULT_DISPLAY),
-                        eventWindowId(windowId),
-                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_TITLE)));
-    }
-
-    private void registerLeashedTokenAndWindowId() {
-        mA11yWindowManager.registerIdLocked(mMockHostToken, HOST_WINDOW_ID);
-        mA11yWindowManager.registerIdLocked(mMockEmbeddedToken, EMBEDDED_WINDOW_ID);
-    }
-
-    private void startTrackingPerDisplay(int displayId) throws RemoteException {
-        ArrayList<AccessibilityWindow> windowsForDisplay = new ArrayList<>();
-        // Adds RemoteAccessibilityConnection into AccessibilityWindowManager, and copy
-        // mock window token into mA11yWindowTokens. Also, preparing WindowInfo mWindowInfos
-        // for the test.
-        for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) {
-            final IWindow token = addAccessibilityInteractionConnection(displayId,
-                    true, USER_SYSTEM_ID);
-            windowsForDisplay.add(createMockAccessibilityWindow(token, displayId));
-
-        }
-        for (int i = 0; i < NUM_APP_WINDOWS; i++) {
-            final IWindow token = addAccessibilityInteractionConnection(displayId,
-                    false, USER_SYSTEM_ID);
-            windowsForDisplay.add(createMockAccessibilityWindow(token, displayId));
-        }
-        // Sets up current focused window of display.
-        // Each display has its own current focused window if config_perDisplayFocusEnabled is true.
-        // Otherwise only default display needs to current focused window.
-        if (mSupportPerDisplayFocus || displayId == Display.DEFAULT_DISPLAY) {
-            windowsForDisplay.get(DEFAULT_FOCUSED_INDEX).getWindowInfo().focused = true;
-        }
-        // Turns on windows tracking, and update window info.
-        mA11yWindowManager.startTrackingWindows(displayId, false);
-        // Puts window lists into array.
-        mWindows.put(displayId, windowsForDisplay);
-        // Sets the default display is the top focused display and
-        // its current focused window is the top focused window.
-        if (displayId == Display.DEFAULT_DISPLAY) {
-            setTopFocusedWindowAndDisplay(displayId, DEFAULT_FOCUSED_INDEX);
-        }
-        // Invokes callback for sending window lists to A11y framework.
-        onAccessibilityWindowsChanged(displayId, FORCE_SEND);
-
-        assertEquals(mA11yWindowManager.getWindowListLocked(displayId).size(),
-                windowsForDisplay.size());
-    }
-
-    private WindowsForAccessibilityCallback getWindowsForAccessibilityCallbacks(int displayId) {
-        ArgumentCaptor<WindowsForAccessibilityCallback> windowsForAccessibilityCallbacksCaptor =
-                ArgumentCaptor.forClass(
-                        WindowsForAccessibilityCallback.class);
-        verify(mMockWindowManagerInternal)
-                .setWindowsForAccessibilityCallback(eq(displayId),
-                        windowsForAccessibilityCallbacksCaptor.capture());
-        return windowsForAccessibilityCallbacksCaptor.getValue();
-    }
-
-    private IWindow addAccessibilityInteractionConnection(int displayId, boolean bGlobal,
-            int userId) throws RemoteException {
-        final IWindow mockWindowToken = Mockito.mock(IWindow.class);
-        final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock(
-                IAccessibilityInteractionConnection.class);
-        final IBinder mockConnectionBinder = Mockito.mock(IBinder.class);
-        final IBinder mockWindowBinder = Mockito.mock(IBinder.class);
-        final IBinder mockLeashToken = Mockito.mock(IBinder.class);
-        when(mockA11yConnection.asBinder()).thenReturn(mockConnectionBinder);
-        when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder);
-        when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(userId))
-                .thenReturn(bGlobal);
-        when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowBinder))
-                .thenReturn(displayId);
-
-        int windowId = mA11yWindowManager.addAccessibilityInteractionConnection(
-                mockWindowToken, mockLeashToken, mockA11yConnection, PACKAGE_NAME, userId);
-        mA11yWindowTokens.put(windowId, mockWindowToken);
-        return mockWindowToken;
-    }
-
-    private int addAccessibilityInteractionConnection(int displayId, boolean bGlobal,
-            IBinder leashToken, int userId) throws RemoteException {
-        final IWindow mockWindowToken = Mockito.mock(IWindow.class);
-        final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock(
-                IAccessibilityInteractionConnection.class);
-        final IBinder mockConnectionBinder = Mockito.mock(IBinder.class);
-        final IBinder mockWindowBinder = Mockito.mock(IBinder.class);
-        when(mockA11yConnection.asBinder()).thenReturn(mockConnectionBinder);
-        when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder);
-        when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(userId))
-                .thenReturn(bGlobal);
-        when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowBinder))
-                .thenReturn(displayId);
-
-        int windowId = mA11yWindowManager.addAccessibilityInteractionConnection(
-                mockWindowToken, leashToken, mockA11yConnection, PACKAGE_NAME, userId);
-        mA11yWindowTokens.put(windowId, mockWindowToken);
-        return windowId;
-    }
-
-    private int getWindowIdFromWindowInfosForDisplay(int displayId, int index) {
-        final IBinder windowToken = mWindows.get(displayId).get(index).getWindowInfo().token;
-        return mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, windowToken);
-    }
-
-    private void setTopFocusedWindowAndDisplay(int displayId, int index) {
-        // Sets the top focus window.
-        mTopFocusedWindowToken = mWindows.get(displayId).get(index).getWindowInfo().token;
-        // Sets the top focused display.
-        mTopFocusedDisplayId = displayId;
-    }
-
-    private void onAccessibilityWindowsChanged(int displayId, boolean forceSend) {
-        WindowsForAccessibilityCallback callbacks = mCallbackOfWindows.get(displayId);
-        if (callbacks == null) {
-            callbacks = getWindowsForAccessibilityCallbacks(displayId);
-            mCallbackOfWindows.put(displayId, callbacks);
-        }
-        callbacks.onAccessibilityWindowsChanged(forceSend, mTopFocusedDisplayId,
-                mTopFocusedWindowToken, new Point(SCREEN_WIDTH, SCREEN_HEIGHT),
-                mWindows.get(displayId));
-    }
-
-    private void changeFocusedWindowOnDisplayPerDisplayFocusConfig(
-            int changeFocusedDisplayId, int newFocusedWindowIndex, int oldTopFocusedDisplayId,
-            int oldFocusedWindowIndex) {
-        if (mSupportPerDisplayFocus) {
-            // Gets the old focused window of display which wants to change focused window.
-            WindowInfo focusedWindowInfo =
-                    mWindows.get(changeFocusedDisplayId).get(oldFocusedWindowIndex).getWindowInfo();
-            // Resets the focus of old focused window.
-            focusedWindowInfo.focused = false;
-            // Gets the new window of display which wants to change focused window.
-            focusedWindowInfo =
-                    mWindows.get(changeFocusedDisplayId).get(newFocusedWindowIndex).getWindowInfo();
-            // Sets the focus of new focused window.
-            focusedWindowInfo.focused = true;
-        } else {
-            // Gets the window of display which wants to change focused window.
-            WindowInfo focusedWindowInfo =
-                    mWindows.get(changeFocusedDisplayId).get(newFocusedWindowIndex).getWindowInfo();
-            // Sets the focus of new focused window.
-            focusedWindowInfo.focused = true;
-            // Gets the old focused window of old top focused display.
-            focusedWindowInfo =
-                    mWindows.get(oldTopFocusedDisplayId).get(oldFocusedWindowIndex).getWindowInfo();
-            // Resets the focus of old focused window.
-            focusedWindowInfo.focused = false;
-            // Changes the top focused display and window.
-            setTopFocusedWindowAndDisplay(changeFocusedDisplayId, newFocusedWindowIndex);
-        }
-    }
-
-    private AccessibilityWindow createMockAccessibilityWindow(IWindow windowToken, int displayId) {
-        final WindowInfo windowInfo = WindowInfo.obtain();
-        windowInfo.type = WindowManager.LayoutParams.TYPE_APPLICATION;
-        windowInfo.token = windowToken.asBinder();
-
-        final AccessibilityWindow window = Mockito.mock(AccessibilityWindow.class);
-        when(window.getWindowInfo()).thenReturn(windowInfo);
-        when(window.isFocused()).thenAnswer(invocation -> windowInfo.focused);
-        when(window.isTouchable()).thenReturn(true);
-        when(window.getType()).thenReturn(windowInfo.type);
-
-        setRegionForMockAccessibilityWindow(window, nextToucableRegion(displayId));
-        return window;
-    }
-
-    private void setRegionForMockAccessibilityWindow(AccessibilityWindow window, Region region) {
-        doAnswer(invocation -> {
-            ((Region) invocation.getArgument(0)).set(region);
-            return null;
-        }).when(window).getTouchableRegionInScreen(any(Region.class));
-        doAnswer(invocation -> {
-            ((Region) invocation.getArgument(0)).set(region);
-            return null;
-        }).when(window).getTouchableRegionInWindow(any(Region.class));
-    }
-
-    private Region nextToucableRegion(int displayId) {
-        final int topLeft = mNextRegionOffsets.get(displayId, 0);
-        final int bottomRight = topLeft + 100;
-        mNextRegionOffsets.put(displayId, topLeft + 10);
-        return new Region(topLeft, topLeft, bottomRight, bottomRight);
-    }
-
-    @Nullable
-    private static String toString(@Nullable CharSequence cs) {
-        return cs == null ? null : cs.toString();
-    }
-
-    static class DisplayIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
-        private final int mDisplayId;
-
-        DisplayIdMatcher(int displayId) {
-            super();
-            mDisplayId = displayId;
-        }
-
-        static DisplayIdMatcher displayId(int displayId) {
-            return new DisplayIdMatcher(displayId);
-        }
-
-        @Override
-        protected boolean matchesSafely(AccessibilityEvent event) {
-            return event.getDisplayId() == mDisplayId;
-        }
-
-        @Override
-        public void describeTo(Description description) {
-            description.appendText("Matching to displayId " + mDisplayId);
-        }
-    }
-
-    static class EventWindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
-        private int mWindowId;
-
-        EventWindowIdMatcher(int windowId) {
-            super();
-            mWindowId = windowId;
-        }
-
-        static EventWindowIdMatcher eventWindowId(int windowId) {
-            return new EventWindowIdMatcher(windowId);
-        }
-
-        @Override
-        protected boolean matchesSafely(AccessibilityEvent event) {
-            return event.getWindowId() == mWindowId;
-        }
-
-        @Override
-        public void describeTo(Description description) {
-            description.appendText("Matching to windowId " + mWindowId);
-        }
-    }
-
-    static class WindowChangesMatcher extends TypeSafeMatcher<AccessibilityEvent> {
-        private int mWindowChanges;
-
-        WindowChangesMatcher(int windowChanges) {
-            super();
-            mWindowChanges = windowChanges;
-        }
-
-        static WindowChangesMatcher a11yWindowChanges(int windowChanges) {
-            return new WindowChangesMatcher(windowChanges);
-        }
-
-        @Override
-        protected boolean matchesSafely(AccessibilityEvent event) {
-            return event.getWindowChanges() == mWindowChanges;
-        }
-
-        @Override
-        public void describeTo(Description description) {
-            description.appendText("Matching to window changes " + mWindowChanges);
-        }
-    }
-
-    static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityWindowInfo> {
-        private final int mWindowId;
-
-        WindowIdMatcher(int windowId) {
-            super();
-            mWindowId = windowId;
-        }
-
-        static WindowIdMatcher windowId(int windowId) {
-            return new WindowIdMatcher(windowId);
-        }
-
-        @Override
-        protected boolean matchesSafely(AccessibilityWindowInfo window) {
-            return window.getId() == mWindowId;
-        }
-
-        @Override
-        public void describeTo(Description description) {
-            description.appendText("Matching to windowId " + mWindowId);
-        }
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
index 7e0c12a..ac27a97 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
@@ -21,7 +21,6 @@
 import static com.android.server.accessibility.Flags.FLAG_MAGNIFICATION_ENLARGE_POINTER_BUGFIX;
 import static com.android.server.accessibility.magnification.FullScreenMagnificationController.MagnificationInfoChangedCallback;
 import static com.android.server.accessibility.magnification.MockMagnificationConnection.TEST_DISPLAY;
-import static com.android.window.flags.Flags.FLAG_ALWAYS_DRAW_MAGNIFICATION_FULLSCREEN_BORDER;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -308,7 +307,6 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(FLAG_ALWAYS_DRAW_MAGNIFICATION_FULLSCREEN_BORDER)
     public void testSetScale_noConnection_doNothing() {
         register(TEST_DISPLAY);
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index f0d3456..c878799 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -57,10 +57,6 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.platform.test.annotations.RequiresFlagsDisabled;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.provider.Settings;
 import android.test.mock.MockContentResolver;
 import android.testing.DexmakerShareClassLoaderRule;
@@ -82,7 +78,6 @@
 import com.android.server.accessibility.test.MessageCapturingHandler;
 import com.android.server.input.InputManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
-import com.android.window.flags.Flags;
 
 import org.junit.After;
 import org.junit.Before;
@@ -101,9 +96,6 @@
 @RunWith(AndroidJUnit4.class)
 public class MagnificationControllerTest {
 
-    @Rule
-    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-
     private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
     private static final int TEST_SERVICE_ID = 1;
     private static final Region INITIAL_SCREEN_MAGNIFICATION_REGION =
@@ -1365,8 +1357,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_ALWAYS_DRAW_MAGNIFICATION_FULLSCREEN_BORDER)
-    public void onFullscreenMagnificationActivationState_systemUiBorderFlagOn_notifyConnection() {
+    public void onFullscreenMagnificationActivationState_notifyConnection() {
         mMagnificationController.onFullScreenMagnificationActivationState(
                 TEST_DISPLAY, /* activated= */ true);
 
@@ -1374,17 +1365,6 @@
                 .onFullscreenMagnificationActivationChanged(TEST_DISPLAY, /* activated= */ true);
     }
 
-    @Test
-    @RequiresFlagsDisabled(Flags.FLAG_ALWAYS_DRAW_MAGNIFICATION_FULLSCREEN_BORDER)
-    public void
-            onFullscreenMagnificationActivationState_systemUiBorderFlagOff_neverNotifyConnection() {
-        mMagnificationController.onFullScreenMagnificationActivationState(
-                TEST_DISPLAY, /* activated= */ true);
-
-        verify(mMagnificationConnectionManager, never())
-                .onFullscreenMagnificationActivationChanged(TEST_DISPLAY, /* activated= */ true);
-    }
-
     private void setMagnificationEnabled(int mode) throws RemoteException {
         setMagnificationEnabled(mode, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
     }
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java
index 1a593dd..42b7f4b 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java
@@ -755,6 +755,7 @@
 
         verify(mActivityListener, after(TIMEOUT_MILLIS).never())
                 .onSecureWindowShown(eq(DISPLAY_ID), eq(activityInfo));
+        verify(mActivityListener, never()).onSecureWindowHidden(eq(DISPLAY_ID));
         verify(mActivityListener, never())
                 .onActivityLaunchBlocked(eq(DISPLAY_ID), eq(activityInfo), any());
     }
@@ -776,6 +777,10 @@
                 .onSecureWindowShown(eq(DISPLAY_ID), eq(activityInfo));
         verify(mActivityListener, after(TIMEOUT_MILLIS).never())
                 .onActivityLaunchBlocked(eq(DISPLAY_ID), eq(activityInfo), any());
+
+        assertThat(gwpc.keepActivityOnWindowFlagsChanged(activityInfo, 0, 0)).isTrue();
+
+        verify(mActivityListener, timeout(TIMEOUT_MILLIS)).onSecureWindowHidden(eq(DISPLAY_ID));
     }
 
     @Test
@@ -794,6 +799,7 @@
 
         verify(mActivityListener, after(TIMEOUT_MILLIS).never())
                 .onSecureWindowShown(eq(DISPLAY_ID), eq(activityInfo));
+        verify(mActivityListener, never()).onSecureWindowHidden(eq(DISPLAY_ID));
         verify(mActivityListener, never())
                 .onActivityLaunchBlocked(eq(DISPLAY_ID), eq(activityInfo), any());
     }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index cf5dc4b..30aa8ce 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4404,6 +4404,7 @@
     }
 
     @Test
+    @Ignore("b/277916462")
     public void testSetAutoTimeEnabledModifiesSetting() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
@@ -4415,6 +4416,7 @@
     }
 
     @Test
+    @Ignore("b/277916462")
     public void testSetAutoTimeEnabledWithPOOnUser0() throws Exception {
         mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
         setupProfileOwnerOnUser0();
@@ -4434,7 +4436,7 @@
     }
 
     @Test
-    @Ignore("b/359188869")
+    @Ignore("b/277916462")
     public void testSetAutoTimeEnabledWithPOOfOrganizationOwnedDevice() throws Exception {
         setupProfileOwner();
         configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
@@ -5034,8 +5036,6 @@
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED)
     public void testSetSecondaryLockscreenEnabled() throws Exception {
-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
-
         verifySetSecondaryLockscreenEnabled(false);
         verifySetSecondaryLockscreenEnabled(true);
     }
@@ -5043,6 +5043,10 @@
     private void verifySetSecondaryLockscreenEnabled(boolean enabled) throws Exception {
         reset(getServices().supervisionManagerInternal);
 
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        doReturn(DpmMockContext.CALLER_UID).when(getServices().packageManagerInternal)
+                .getPackageUid(any(), anyLong(), anyInt());
+
         dpm.setSecondaryLockscreenEnabled(admin1, enabled);
         verify(getServices().supervisionManagerInternal).setSupervisionLockscreenEnabledForUser(
                 CALLER_USER_HANDLE, enabled, null);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
index c7574bd..dd4101e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
@@ -41,11 +41,14 @@
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.tv.cec.V1_0.SendMessageResult;
+import android.media.tv.flags.Flags;
 import android.os.Binder;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.test.TestLooper;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.stats.hdmi.HdmiStatsEnums;
 
 import androidx.test.InstrumentationRegistry;
@@ -54,6 +57,7 @@
 import com.android.server.SystemService;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -83,6 +87,9 @@
     private HdmiEarcController mHdmiEarcController;
     private FakeEarcNativeWrapper mEarcNativeWrapper;
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     @Before
     public void setUp() throws RemoteException {
         mHdmiCecAtomWriterSpy = spy(new HdmiCecAtomWriter());
@@ -232,7 +239,8 @@
                         HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN,
                         HdmiStatsEnums.VOLUME_MUTE,
                         HdmiCecAtomWriter.FEATURE_ABORT_OPCODE_UNKNOWN,
-                        HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN);
+                        HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN,
+                        HdmiCecAtomWriter.PHYSICAL_ADDRESS_INVALID);
     }
 
     @Test
@@ -258,7 +266,8 @@
                         HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN,
                         HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN,
                         HdmiCecAtomWriter.FEATURE_ABORT_OPCODE_UNKNOWN,
-                        HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN);
+                        HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN,
+                        HdmiCecAtomWriter.PHYSICAL_ADDRESS_INVALID);
     }
 
     @Test
@@ -285,7 +294,8 @@
                         HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN,
                         HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN,
                         Constants.MESSAGE_RECORD_ON,
-                        HdmiStatsEnums.UNRECOGNIZED_OPCODE);
+                        HdmiStatsEnums.UNRECOGNIZED_OPCODE,
+                        HdmiCecAtomWriter.PHYSICAL_ADDRESS_INVALID);
     }
 
     @Test
@@ -311,7 +321,8 @@
                         HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN,
                         HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN,
                         HdmiCecAtomWriter.FEATURE_ABORT_OPCODE_UNKNOWN,
-                        HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN);
+                        HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN,
+                        HdmiCecAtomWriter.PHYSICAL_ADDRESS_INVALID);
     }
 
     @Test
@@ -337,6 +348,59 @@
     }
 
     @Test
+    @EnableFlags({Flags.FLAG_HDMI_CONTROL_COLLECT_PHYSICAL_ADDRESS})
+    public void testMessageReported_writesAtom_reportPhysicalAddress() {
+        HdmiCecMessage message = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+                ADDR_PLAYBACK_1, 0x1234, HdmiDeviceInfo.DEVICE_PLAYBACK);
+
+        mHdmiCecAtomWriterSpy.messageReported(
+                message,
+                HdmiStatsEnums.INCOMING,
+                1234);
+
+        verify(mHdmiCecAtomWriterSpy, times(1))
+                .writeHdmiCecMessageReportedAtom(
+                        1234,
+                        HdmiStatsEnums.INCOMING,
+                        Constants.ADDR_PLAYBACK_1,
+                        Constants.ADDR_BROADCAST,
+                        Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS,
+                        HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN,
+                        HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN,
+                        HdmiCecAtomWriter.FEATURE_ABORT_OPCODE_UNKNOWN,
+                        HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN,
+                        0x1234);
+    }
+
+    @Test
+    @EnableFlags({Flags.FLAG_HDMI_CONTROL_COLLECT_PHYSICAL_ADDRESS})
+    public void testMessageReported_writesAtom_reportPhysicalAddress_noParams() {
+        HdmiCecMessage message = HdmiCecMessage.build(
+                Constants.ADDR_PLAYBACK_1,
+                Constants.ADDR_BROADCAST,
+                Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS,
+                new byte[0]);
+
+        mHdmiCecAtomWriterSpy.messageReported(
+                message,
+                HdmiStatsEnums.INCOMING,
+                1234);
+
+        verify(mHdmiCecAtomWriterSpy, times(1))
+                .writeHdmiCecMessageReportedAtom(
+                        1234,
+                        HdmiStatsEnums.INCOMING,
+                        Constants.ADDR_PLAYBACK_1,
+                        Constants.ADDR_BROADCAST,
+                        Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS,
+                        HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN,
+                        HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN,
+                        HdmiCecAtomWriter.FEATURE_ABORT_OPCODE_UNKNOWN,
+                        HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN,
+                        HdmiCecAtomWriter.PHYSICAL_ADDRESS_INVALID);
+    }
+
+    @Test
     public void testDsmStatusChanged_onWakeUp_ArcSupported_writesAtom_logReasonWake() {
         mHdmiControlServiceSpy.setSoundbarMode(HdmiControlManager.SOUNDBAR_MODE_DISABLED);
         Mockito.clearInvocations(mHdmiCecAtomWriterSpy);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index 0816e7b..5be4490 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -118,6 +118,7 @@
     private boolean mDisableCecOnStandbyByLowEnergyMode;
     private boolean mWasCecDisabledOnStandbyByLowEnergyMode;
     private boolean mUseHdmiCecPowerStatusController;
+    private boolean mUserEnabledCecInOfflineMode;
 
     private class DeviceEventListener {
         private HdmiDeviceInfo mDevice;
@@ -250,6 +251,11 @@
                     protected void setWasCecDisabledOnStandbyByLowEnergyMode(boolean value) {
                         mWasCecDisabledOnStandbyByLowEnergyMode = value;
                     }
+
+                    @Override
+                    protected boolean userEnabledCecInOfflineMode() {
+                        return mUserEnabledCecInOfflineMode;
+                    }
                 };
 
         mHdmiControlService.setIoLooper(mMyLooper);
@@ -298,6 +304,7 @@
         mWasCecDisabledOnStandbyByLowEnergyMode = false;
         mDisableCecOnStandbyByLowEnergyMode = false;
         mUseHdmiCecPowerStatusController = false;
+        mUserEnabledCecInOfflineMode = false;
         mNativeWrapper.clearResultMessages();
     }
 
@@ -2400,6 +2407,32 @@
         assertTrue(mVendorCommandListeners.contains(vendorCommandListenerInvocationSettingChange));
     }
 
+    @Test
+    public void lowEnergyMode_userEnabledCecInOfflineMode_onStandby_cecStaysEnabled() {
+        mDisableCecOnStandbyByLowEnergyMode = true;
+        mUseHdmiCecPowerStatusController = true;
+        mUserEnabledCecInOfflineMode = true;
+        mPowerManager.setIsLowPowerStandbyEnabled(true);
+
+        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+                        HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+                HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+                        HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+                HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        assertFalse(mWasCecDisabledOnStandbyByLowEnergyMode);
+        mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+                        HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+                HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        assertFalse(mWasCecDisabledOnStandbyByLowEnergyMode);
+    }
+
     protected static class MockTvDevice extends HdmiCecLocalDeviceTv {
         MockTvDevice(HdmiControlService service) {
             super(service);
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
index b2a7d20..3ced56a 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
@@ -67,10 +67,12 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.ApplicationInfoFlags;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.Rect;
 import android.media.projection.IMediaProjection;
 import android.media.projection.IMediaProjectionCallback;
 import android.media.projection.IMediaProjectionWatcherCallback;
 import android.media.projection.ReviewGrantedConsentResult;
+import android.media.projection.StopReason;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Looper;
@@ -549,7 +551,7 @@
         MediaProjectionManagerService.MediaProjection projection =
                 startProjectionPreconditions(service);
 
-        projection.stop();
+        projection.stop(StopReason.STOP_UNKNOWN);
 
         verifyZeroInteractions(mMediaProjectionMetricsLogger);
     }
@@ -562,10 +564,10 @@
                 startProjectionPreconditions(service);
         projection.start(mIMediaProjectionCallback);
 
-        projection.stop();
+        final @StopReason int stopReason = StopReason.STOP_UNKNOWN;
+        projection.stop(stopReason);
 
-        verify(mMediaProjectionMetricsLogger)
-                .logStopped(UID, TARGET_UID_UNKNOWN);
+        verify(mMediaProjectionMetricsLogger).logStopped(UID, TARGET_UID_UNKNOWN, stopReason);
     }
 
     @Test
@@ -580,15 +582,16 @@
                 .setContentRecordingSession(any(ContentRecordingSession.class));
         service.setContentRecordingSession(DISPLAY_SESSION);
 
-        projection.stop();
+        final @StopReason int stopReason = StopReason.STOP_UNKNOWN;
+        projection.stop(stopReason);
 
-        verify(mMediaProjectionMetricsLogger)
-                .logStopped(UID, TARGET_UID_FULL_SCREEN);
+        verify(mMediaProjectionMetricsLogger).logStopped(UID, TARGET_UID_FULL_SCREEN, stopReason);
     }
 
     @Test
     public void stop_taskSession_logsHostUidAndTargetUid() throws Exception {
         int targetUid = 1234;
+        int stopReason = StopReason.STOP_UNKNOWN;
         MediaProjectionManagerService service =
                 new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
         MediaProjectionManagerService.MediaProjection projection =
@@ -601,9 +604,9 @@
         taskSession.setTargetUid(targetUid);
         service.setContentRecordingSession(taskSession);
 
-        projection.stop();
+        projection.stop(stopReason);
 
-        verify(mMediaProjectionMetricsLogger).logStopped(UID, targetUid);
+        verify(mMediaProjectionMetricsLogger).logStopped(UID, targetUid, stopReason);
     }
 
     @Test
@@ -638,7 +641,7 @@
         projection.start(mIMediaProjectionCallback);
         assertThat(projection.isValid()).isTrue();
 
-        projection.stop();
+        projection.stop(StopReason.STOP_UNKNOWN);
 
         // Second start - so not valid.
         projection.start(mIMediaProjectionCallback);
@@ -692,7 +695,7 @@
         MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(
                 service);
         projection.start(mIMediaProjectionCallback);
-        projection.stop();
+        projection.stop(StopReason.STOP_UNKNOWN);
         // Second start - so not valid.
         projection.start(mIMediaProjectionCallback);
 
@@ -708,7 +711,7 @@
         MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(
                 service);
         projection.start(mIMediaProjectionCallback);
-        projection.stop();
+        projection.stop(StopReason.STOP_UNKNOWN);
 
         // Second start - so not valid.
         projection.start(mIMediaProjectionCallback);
@@ -947,6 +950,26 @@
                 projection.uid, targetUid, WINDOWING_MODE_MULTI_WINDOW);
     }
 
+    @Test
+    public void notifyCaptureBoundsChanged_forwardsToLoggerAndResizeCallbacks() throws Exception {
+        int targetUid = 123;
+        mService =
+                new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
+
+        ContentRecordingSession taskSession = createTaskSession(mock(IBinder.class));
+        taskSession.setTargetUid(targetUid);
+        mService.setContentRecordingSession(taskSession);
+
+        MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
+        projection.start(mIMediaProjectionCallback);
+
+        Rect newBounds = new Rect(0, 0, 1000, 2000);
+        mService.notifyCaptureBoundsChanged(RECORD_CONTENT_TASK, targetUid, newBounds);
+
+        verify(mMediaProjectionMetricsLogger)
+                .logChangedCaptureBounds(RECORD_CONTENT_TASK, projection.uid, targetUid, newBounds);
+    }
+
     /**
      * Executes and validates scenario where the consent result indicates the projection ends.
      */
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java
index 72ce9fe..c727bb6 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java
@@ -32,6 +32,17 @@
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_DEVICE_LOCK;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_ERROR;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_FOREGROUND_SERVICE_CHANGE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_HOST_APP_STOP;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_MEDIA_ROUTE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_PROJECTION;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_QS_TILE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_STATUS_BAR_CHIP_STOP;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_TASK_APP_CLOSE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_USER_SWITCH;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_APP_TASK;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_DISPLAY;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_UNKNOWN;
@@ -46,6 +57,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.media.projection.StopReason;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -81,6 +93,7 @@
 
     private static final int TEST_WINDOWING_MODE = 987;
     private static final int TEST_CONTENT_TO_RECORD = 654;
+    private static final int TEST_STOP_SOURCE = 321;
 
     @Mock private FrameworkStatsLogWrapper mFrameworkStatsLogWrapper;
     @Mock private MediaProjectionSessionIdGenerator mSessionIdGenerator;
@@ -136,6 +149,14 @@
     }
 
     @Test
+    public void logInitiated_logsUnknownStopSource() {
+        mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
+
+        verifyStopSourceLogged(
+                MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+    }
+
+    @Test
     public void logInitiated_noPreviousSession_logsUnknownTimeSinceLastActive() {
         when(mTimestampStore.timeSinceLastActiveSession()).thenReturn(null);
 
@@ -177,7 +198,7 @@
 
     @Test
     public void logStopped_logsStateChangedAtomId() {
-        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
 
         verifyStateChangedAtomIdLogged();
     }
@@ -187,42 +208,49 @@
         int currentSessionId = 987;
         when(mSessionIdGenerator.getCurrentSessionId()).thenReturn(currentSessionId);
 
-        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
 
         verifySessionIdLogged(currentSessionId);
     }
 
     @Test
     public void logStopped_logsStateStopped() {
-        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
 
         verifyStateLogged(MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED);
     }
 
     @Test
     public void logStopped_logsHostUid() {
-        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
 
         verifyStateChangedHostUidLogged(TEST_HOST_UID);
     }
 
     @Test
     public void logStopped_logsTargetUid() {
-        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
 
         verifyStageChangedTargetUidLogged(TEST_TARGET_UID);
     }
 
     @Test
+    public void logStopped_logsStopSource() {
+        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, StopReason.STOP_UNKNOWN);
+
+        verifyStopSourceLogged(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+    }
+
+    @Test
     public void logStopped_logsUnknownTimeSinceLastActive() {
-        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
 
         verifyTimeSinceLastActiveSessionLogged(-1);
     }
 
     @Test
     public void logStopped_logsUnknownSessionCreationSource() {
-        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
 
         verifyCreationSourceLogged(
                 MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
@@ -230,7 +258,7 @@
 
     @Test
     public void logStopped_logsPreviousState() {
-        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
         verifyPreviousStateLogged(
                 MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN);
 
@@ -238,7 +266,7 @@
         verifyPreviousStateLogged(
                 MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED);
 
-        mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE);
+        mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE, TEST_STOP_SOURCE);
         verifyPreviousStateLogged(
                 MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED);
     }
@@ -247,14 +275,14 @@
     public void logStopped_capturingWasInProgress_registersActiveSessionEnded() {
         mLogger.logInProgress(TEST_HOST_UID, TEST_TARGET_UID);
 
-        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
 
         verify(mTimestampStore).registerActiveSessionEnded();
     }
 
     @Test
     public void logStopped_capturingWasNotInProgress_doesNotRegistersActiveSessionEnded() {
-        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+        mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
 
         verify(mTimestampStore, never()).registerActiveSessionEnded();
     }
@@ -314,6 +342,14 @@
     }
 
     @Test
+    public void logInProgress_logsUnknownSessionStopSource() {
+        mLogger.logInProgress(TEST_HOST_UID, TEST_TARGET_UID);
+
+        verifyStopSourceLogged(
+                MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+    }
+
+    @Test
     public void logInProgress_logsPreviousState() {
         mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
         verifyPreviousStateLogged(
@@ -323,7 +359,7 @@
         verifyPreviousStateLogged(
                 MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED);
 
-        mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE);
+        mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE, TEST_STOP_SOURCE);
         verifyPreviousStateLogged(
                 MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS);
 
@@ -387,6 +423,14 @@
     }
 
     @Test
+    public void logPermissionRequestDisplayed_logsUnknownSessionStopSource() {
+        mLogger.logPermissionRequestDisplayed(TEST_HOST_UID);
+
+        verifyStopSourceLogged(
+                MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+    }
+
+    @Test
     public void logPermissionRequestDisplayed_logsPreviousState() {
         mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
         verifyPreviousStateLogged(
@@ -396,7 +440,7 @@
         verifyPreviousStateLogged(
                 MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED);
 
-        mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE);
+        mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE, TEST_STOP_SOURCE);
         verifyPreviousStateLogged(
                 MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED);
 
@@ -460,6 +504,14 @@
     }
 
     @Test
+    public void logAppSelectorDisplayed_logsUnknownSessionStopSource() {
+        mLogger.logAppSelectorDisplayed(TEST_HOST_UID);
+
+        verifyStopSourceLogged(
+                MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+    }
+
+    @Test
     public void logAppSelectorDisplayed_logsPreviousState() {
         mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
         verifyPreviousStateLogged(
@@ -469,7 +521,7 @@
         verifyPreviousStateLogged(
                 MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED);
 
-        mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE);
+        mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE, TEST_STOP_SOURCE);
         verifyPreviousStateLogged(
                 MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_APP_SELECTOR_DISPLAYED);
 
@@ -536,6 +588,14 @@
     }
 
     @Test
+    public void logProjectionPermissionRequestCancelled_logsUnknownStopSource() {
+        mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID);
+
+        verifyStopSourceLogged(
+                MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+    }
+
+    @Test
     public void logWindowingModeChanged_logsTargetChangedAtomId() {
         mLogger.logChangedWindowingMode(
                 TEST_CONTENT_TO_RECORD, TEST_HOST_UID, TEST_TARGET_UID, TEST_WINDOWING_MODE);
@@ -614,6 +674,42 @@
                 .isEqualTo(MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_UNKNOWN);
     }
 
+    @Test
+    public void testStopReasonToSessionStopSource() {
+        mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_HOST_APP))
+                .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_HOST_APP_STOP);
+
+        mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_TARGET_REMOVED))
+                .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_TASK_APP_CLOSE);
+
+        mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_DEVICE_LOCKED))
+                .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_DEVICE_LOCK);
+
+        mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_PRIVACY_CHIP))
+                .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_STATUS_BAR_CHIP_STOP);
+
+        mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_QS_TILE))
+                .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_QS_TILE);
+
+        mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_USER_SWITCH))
+                .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_USER_SWITCH);
+
+        mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_FOREGROUND_SERVICE_CHANGE))
+                .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_FOREGROUND_SERVICE_CHANGE);
+
+        mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_NEW_PROJECTION))
+                .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_PROJECTION);
+
+        mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_NEW_MEDIA_ROUTE))
+                .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_MEDIA_ROUTE);
+
+        mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_ERROR))
+                .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_ERROR);
+
+        mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_UNKNOWN))
+                .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+    }
+
     private void verifyStateChangedAtomIdLogged() {
         verify(mFrameworkStatsLogWrapper)
                 .writeStateChanged(
@@ -624,7 +720,8 @@
                         /* hostUid= */ anyInt(),
                         /* targetUid= */ anyInt(),
                         /* timeSinceLastActive= */ anyInt(),
-                        /* creationSource= */ anyInt());
+                        /* creationSource= */ anyInt(),
+                        /* stopSource= */ anyInt());
     }
 
     private void verifyStateLogged(int state) {
@@ -637,7 +734,8 @@
                         /* hostUid= */ anyInt(),
                         /* targetUid= */ anyInt(),
                         /* timeSinceLastActive= */ anyInt(),
-                        /* creationSource= */ anyInt());
+                        /* creationSource= */ anyInt(),
+                        /* stopSource= */ anyInt());
     }
 
     private void verifyStateChangedHostUidLogged(int hostUid) {
@@ -650,7 +748,8 @@
                         eq(hostUid),
                         /* targetUid= */ anyInt(),
                         /* timeSinceLastActive= */ anyInt(),
-                        /* creationSource= */ anyInt());
+                        /* creationSource= */ anyInt(),
+                        /* stopSource= */ anyInt());
     }
 
     private void verifyCreationSourceLogged(int creationSource) {
@@ -663,7 +762,22 @@
                         /* hostUid= */ anyInt(),
                         /* targetUid= */ anyInt(),
                         /* timeSinceLastActive= */ anyInt(),
-                        eq(creationSource));
+                        eq(creationSource),
+                        /* stopSource= */ anyInt());
+    }
+
+    private void verifyStopSourceLogged(int stopSource) {
+        verify(mFrameworkStatsLogWrapper)
+                .writeStateChanged(
+                        /* code= */ anyInt(),
+                        /* sessionId= */ anyInt(),
+                        /* state= */ anyInt(),
+                        /* previousState= */ anyInt(),
+                        /* hostUid= */ anyInt(),
+                        /* targetUid= */ anyInt(),
+                        /* timeSinceLastActive= */ anyInt(),
+                        /* stopSource= */ anyInt(),
+                        eq(stopSource));
     }
 
     private void verifyStageChangedTargetUidLogged(int targetUid) {
@@ -676,7 +790,8 @@
                         /* hostUid= */ anyInt(),
                         eq(targetUid),
                         /* timeSinceLastActive= */ anyInt(),
-                        /* creationSource= */ anyInt());
+                        /* creationSource= */ anyInt(),
+                        /* stopSource= */ anyInt());
     }
 
     private void verifyTimeSinceLastActiveSessionLogged(int timeSinceLastActiveSession) {
@@ -689,7 +804,8 @@
                         /* hostUid= */ anyInt(),
                         /* targetUid= */ anyInt(),
                         /* timeSinceLastActive= */ eq(timeSinceLastActiveSession),
-                        /* creationSource= */ anyInt());
+                        /* creationSource= */ anyInt(),
+                        /* stopSource= */ anyInt());
     }
 
     private void verifySessionIdLogged(int newSessionId) {
@@ -702,7 +818,8 @@
                         /* hostUid= */ anyInt(),
                         /* targetUid= */ anyInt(),
                         /* timeSinceLastActive= */ anyInt(),
-                        /* creationSource= */ anyInt());
+                        /* creationSource= */ anyInt(),
+                        /* stopSource= */ anyInt());
     }
 
     private void verifyPreviousStateLogged(int previousState) {
@@ -715,7 +832,8 @@
                         /* hostUid= */ anyInt(),
                         /* targetUid= */ anyInt(),
                         /* timeSinceLastActive= */ anyInt(),
-                        /* creationSource= */ anyInt());
+                        /* creationSource= */ anyInt(),
+                        /* stopSource= */ anyInt());
     }
 
     private void verifyTargetChangedAtomIdLogged() {
@@ -726,7 +844,12 @@
                         /* targetType= */ anyInt(),
                         /* hostUid= */ anyInt(),
                         /* targetUid= */ anyInt(),
-                        /* targetWindowingMode= */ anyInt());
+                        /* targetWindowingMode= */ anyInt(),
+                        /* width= */ anyInt(),
+                        /* height= */ anyInt(),
+                        /* centerX= */ anyInt(),
+                        /* centerY= */ anyInt(),
+                        /* targetChangeType= */ anyInt());
     }
 
     private void verifyTargetTypeLogged(int targetType) {
@@ -737,7 +860,12 @@
                         eq(targetType),
                         /* hostUid= */ anyInt(),
                         /* targetUid= */ anyInt(),
-                        /* targetWindowingMode= */ anyInt());
+                        /* targetWindowingMode= */ anyInt(),
+                        /* width= */ anyInt(),
+                        /* height= */ anyInt(),
+                        /* centerX= */ anyInt(),
+                        /* centerY= */ anyInt(),
+                        /* targetChangeType= */ anyInt());
     }
 
     private void verifyTargetChangedHostUidLogged(int hostUid) {
@@ -748,7 +876,12 @@
                         /* targetType= */ anyInt(),
                         eq(hostUid),
                         /* targetUid= */ anyInt(),
-                        /* targetWindowingMode= */ anyInt());
+                        /* targetWindowingMode= */ anyInt(),
+                        /* width= */ anyInt(),
+                        /* height= */ anyInt(),
+                        /* centerX= */ anyInt(),
+                        /* centerY= */ anyInt(),
+                        /* targetChangeType= */ anyInt());
     }
 
     private void verifyTargetChangedTargetUidLogged(int targetUid) {
@@ -759,7 +892,12 @@
                         /* targetType= */ anyInt(),
                         /* hostUid= */ anyInt(),
                         eq(targetUid),
-                        /* targetWindowingMode= */ anyInt());
+                        /* targetWindowingMode= */ anyInt(),
+                        /* width= */ anyInt(),
+                        /* height= */ anyInt(),
+                        /* centerX= */ anyInt(),
+                        /* centerY= */ anyInt(),
+                        /* targetChangeType= */ anyInt());
     }
 
     private void verifyWindowingModeLogged(int targetWindowingMode) {
@@ -770,6 +908,11 @@
                         /* targetType= */ anyInt(),
                         /* hostUid= */ anyInt(),
                         /* targetUid= */ anyInt(),
-                        eq(targetWindowingMode));
+                        eq(targetWindowingMode),
+                        /* width= */ anyInt(),
+                        /* height= */ anyInt(),
+                        /* centerX= */ anyInt(),
+                        /* centerY= */ anyInt(),
+                        /* targetChangeType= */ anyInt());
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerCacheTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerCacheTest.java
new file mode 100644
index 0000000..d69e476
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerCacheTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2011 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.pm;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.app.ActivityManager;
+import android.app.LocaleManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.multiuser.Flags;
+import android.os.LocaleList;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.platform.test.annotations.Postsubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.util.ArraySet;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+/**
+ * Test {@link UserManager Cache} functionality.
+ *
+ * atest com.android.server.pm.UserManagerCacheTest
+ */
+@Postsubmit
+@RunWith(AndroidJUnit4.class)
+public final class UserManagerCacheTest {
+
+    private static final LocaleList TEST_LOCALE_LIST = LocaleList.forLanguageTags("pl-PL");
+    private static final long SLEEP_TIMEOUT = 5_000;
+    private static final int REMOVE_USER_TIMEOUT_SECONDS = 180; // 180 seconds
+    private static final String TAG = UserManagerCacheTest.class.getSimpleName();
+
+    private final Context mContext =
+            InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+    private UserManager mUserManager = null;
+    private PackageManager mPackageManager;
+    private LocaleManager mLocaleManager;
+    private ArraySet<Integer> mUsersToRemove;
+    private UserRemovalWaiter mUserRemovalWaiter;
+    private int mOriginalCurrentUserId;
+    private LocaleList mSystemLocales;
+
+    @Before
+    public void setUp() throws Exception {
+        mOriginalCurrentUserId = ActivityManager.getCurrentUser();
+        mUserManager = UserManager.get(mContext);
+        mPackageManager = mContext.getPackageManager();
+        mLocaleManager = mContext.getSystemService(LocaleManager.class);
+        mSystemLocales = mLocaleManager.getSystemLocales();
+        mUserRemovalWaiter = new UserRemovalWaiter(mContext, TAG, REMOVE_USER_TIMEOUT_SECONDS);
+        mUsersToRemove = new ArraySet<>();
+        removeExistingUsers();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        // Making a copy of mUsersToRemove to avoid ConcurrentModificationException
+        mUsersToRemove.stream().toList().forEach(this::removeUser);
+        mUserRemovalWaiter.close();
+        mUserManager.setUserRestriction(UserManager.DISALLOW_GRANT_ADMIN, false,
+                mContext.getUser());
+        mLocaleManager.setSystemLocales(mSystemLocales);
+    }
+
+    private void removeExistingUsers() {
+        int currentUser = ActivityManager.getCurrentUser();
+
+        UserHandle communalProfile = mUserManager.getCommunalProfile();
+        int communalProfileId = communalProfile != null
+                ? communalProfile.getIdentifier() : UserHandle.USER_NULL;
+
+        List<UserInfo> list = mUserManager.getUsers();
+        for (UserInfo user : list) {
+            // Keep system and current user
+            if (user.id != UserHandle.USER_SYSTEM
+                    && user.id != currentUser
+                    && user.id != communalProfileId
+                    && !user.isMain()) {
+                removeUser(user.id);
+            }
+        }
+    }
+
+    @MediumTest
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_CACHE_USER_INFO_READ_ONLY)
+    public void testUserInfoAfterLocaleChange() throws Exception {
+        UserInfo userInfo = mUserManager.createGuest(mContext);
+        mUsersToRemove.add(userInfo.id);
+        assertThat(userInfo).isNotNull();
+
+        UserInfo guestUserInfo = mUserManager.getUserInfo(userInfo.id);
+        assertThat(guestUserInfo).isNotNull();
+        assertThat(guestUserInfo.name).isNotEqualTo("Gość");
+
+        UserInfo ownerUserInfo = mUserManager.getUserInfo(mOriginalCurrentUserId);
+        assertThat(ownerUserInfo).isNotNull();
+        assertThat(ownerUserInfo.name).isNotEqualTo("Właściciel");
+
+        mLocaleManager.setSystemLocales(TEST_LOCALE_LIST);
+        SystemClock.sleep(SLEEP_TIMEOUT);
+        UserInfo guestUserInfoPl = mUserManager.getUserInfo(userInfo.id);
+        UserInfo ownerUserInfoPl = mUserManager.getUserInfo(mOriginalCurrentUserId);
+
+        assertThat(guestUserInfoPl).isNotNull();
+        assertThat(guestUserInfoPl.name).isEqualTo("Gość");
+
+        assertThat(ownerUserInfoPl).isNotNull();
+        assertThat(ownerUserInfoPl.name).isEqualTo("Właściciel");
+    }
+
+
+    @MediumTest
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_CACHE_USER_INFO_READ_ONLY)
+    public void testGetUserInfo10kSpam() throws Exception {
+        UserInfo cachedUserInfo = mUserManager.getUserInfo(mOriginalCurrentUserId);
+        for (int i = 0; i < 10000; i++) {
+            // Control how often cache is calling the API
+            UserInfo ownerUserInfo = mUserManager.getUserInfo(mOriginalCurrentUserId);
+            assertThat(ownerUserInfo).isNotNull();
+            // If indeed it was chached then objects should stay the same. We use == to compare
+            // object addresses to make sure UserInfo is not new copy of the same UserInfo.
+            assertThat(cachedUserInfo.toFullString()).isEqualTo(ownerUserInfo.toFullString());
+        }
+    }
+
+
+    @MediumTest
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_CACHE_USER_INFO_READ_ONLY)
+    public void testSetUserAdmin() throws Exception {
+        UserInfo userInfo = mUserManager.createUser("SecondaryUser",
+                UserManager.USER_TYPE_FULL_SECONDARY, /*flags=*/ 0);
+        mUsersToRemove.add(userInfo.id);
+        // cache user
+        UserInfo cachedUserInfo = mUserManager.getUserInfo(userInfo.id);
+
+        assertThat(userInfo.isAdmin()).isFalse();
+        assertThat(cachedUserInfo.isAdmin()).isFalse();
+
+        // invalidate cache
+        mUserManager.setUserAdmin(userInfo.id);
+
+        // updated UserInfo should be returned
+        cachedUserInfo = mUserManager.getUserInfo(userInfo.id);
+        assertThat(cachedUserInfo.isAdmin()).isTrue();
+    }
+
+
+    @MediumTest
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_CACHE_USER_INFO_READ_ONLY)
+    public void testRevokeUserAdmin() throws Exception {
+        UserInfo userInfo = mUserManager.createUser("Admin",
+                UserManager.USER_TYPE_FULL_SECONDARY, /*flags=*/ UserInfo.FLAG_ADMIN);
+        mUsersToRemove.add(userInfo.id);
+        // cache user
+        UserInfo cachedUserInfo = mUserManager.getUserInfo(userInfo.id);
+        assertThat(userInfo.isAdmin()).isTrue();
+        assertThat(cachedUserInfo.isAdmin()).isTrue();
+
+        // invalidate cache
+        mUserManager.revokeUserAdmin(userInfo.id);
+
+        // updated UserInfo should be returned
+        cachedUserInfo = mUserManager.getUserInfo(userInfo.id);
+        assertThat(cachedUserInfo.isAdmin()).isFalse();
+    }
+
+    @MediumTest
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_CACHE_USER_INFO_READ_ONLY)
+    public void testRevokeUserAdminFromNonAdmin() throws Exception {
+        UserInfo userInfo = mUserManager.createUser("NonAdmin",
+                UserManager.USER_TYPE_FULL_SECONDARY, /*flags=*/ 0);
+        mUsersToRemove.add(userInfo.id);
+        // cache user
+        UserInfo cachedUserInfo = mUserManager.getUserInfo(userInfo.id);
+        assertThat(userInfo.isAdmin()).isFalse();
+        assertThat(cachedUserInfo.isAdmin()).isFalse();
+
+        // invalidate cache
+        mUserManager.revokeUserAdmin(userInfo.id);
+
+        // updated UserInfo should be returned
+        cachedUserInfo = mUserManager.getUserInfo(userInfo.id);
+        assertThat(cachedUserInfo.isAdmin()).isFalse();
+    }
+
+
+    @MediumTest
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_CACHE_USER_INFO_READ_ONLY)
+    public void testSetUserName_withContextUserId() throws Exception {
+        assumeManagedUsersSupported();
+        final String newName = "Managed_user 1";
+        final int mainUserId = mUserManager.getMainUser().getIdentifier();
+
+        // cache main user
+        UserInfo mainUserInfo =  mUserManager.getUserInfo(mainUserId);
+
+        assertThat(mainUserInfo).isNotNull();
+
+        // invalidate cache
+        UserInfo userInfo =  mUserManager.createProfileForUser("Managed 1",
+                UserManager.USER_TYPE_PROFILE_MANAGED,  0, mainUserId, null);
+        mUsersToRemove.add(userInfo.id);
+        // cache user
+        UserInfo cachedUserInfo = mUserManager.getUserInfo(userInfo.id);
+        // updated cache for main user
+        mainUserInfo =  mUserManager.getUserInfo(mainUserId);
+
+        assertThat(userInfo).isNotNull();
+        assertThat(cachedUserInfo).isNotNull();
+        assertThat(mainUserInfo).isNotNull();
+        // profileGroupId are the same after adding profile to user.
+        assertThat(mainUserInfo.profileGroupId).isEqualTo(cachedUserInfo.profileGroupId);
+
+        UserManager um = (UserManager) mContext.createPackageContextAsUser(
+                        "android", 0, userInfo.getUserHandle())
+                .getSystemService(Context.USER_SERVICE);
+        // invalidate cache
+        um.setUserName(newName);
+
+        // updated UserInfo should be returned
+        cachedUserInfo = mUserManager.getUserInfo(userInfo.id);
+        assertThat(cachedUserInfo.name).isEqualTo(newName);
+
+        // get user name from getUserName using context.getUserId
+        assertThat(um.getUserName()).isEqualTo(newName);
+    }
+
+    private void assumeManagedUsersSupported() {
+        // In Automotive, if headless system user is enabled, a managed user cannot be created
+        // under a primary user.
+        assumeTrue("device doesn't support managed users",
+                mPackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS)
+                        && (!isAutomotive() || !UserManager.isHeadlessSystemUserMode()));
+    }
+
+    private void removeUser(int userId) {
+        mUserManager.removeUser(userId);
+        mUserRemovalWaiter.waitFor(userId);
+        mUsersToRemove.remove(userId);
+    }
+
+    private boolean isAutomotive() {
+        return mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java b/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java
index 24bf6ca..b1df0f1 100644
--- a/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java
@@ -60,7 +60,7 @@
     public void setup() throws Settings.SettingNotFoundException {
         mContext = mock(Context.class);
         mPermissionEnforcer = new FakePermissionEnforcer();
-        mPermissionEnforcer.grant(Manifest.permission.SET_ADVANCED_PROTECTION_MODE);
+        mPermissionEnforcer.grant(Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE);
         mPermissionEnforcer.grant(Manifest.permission.QUERY_ADVANCED_PROTECTION_MODE);
 
         mStore = new AdvancedProtectionService.AdvancedProtectionStore(mContext) {
@@ -299,7 +299,7 @@
 
     @Test
     public void testSetProtection_withoutPermission() {
-        mPermissionEnforcer.revoke(Manifest.permission.SET_ADVANCED_PROTECTION_MODE);
+        mPermissionEnforcer.revoke(Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE);
         assertThrows(SecurityException.class, () -> mService.setAdvancedProtectionEnabled(true));
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index 3bc089f..842c441 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -691,6 +691,40 @@
         assertThat(actual).isEqualTo(expected);
     }
 
+    /**
+     * Tests that readPermissions works correctly for the tags:
+     * disabled-in-sku, enabled-in-sku-override.
+     * I.e. that disabled-in-sku add package to block list and
+     * enabled-in-sku-override removes package from the list.
+     */
+    @Test
+    public void testDisablePackageInSku() throws Exception {
+        final String disable_in_sku =
+                "<config>\n"
+                        + "    <disabled-in-sku package=\"com.sony.product1.app\"/>\n"
+                        + "    <disabled-in-sku package=\"com.sony.product2.app\"/>\n"
+                        + "</config>\n";
+
+        final String enable_in_sku_override =
+                "<config>\n"
+                        + "    <enabled-in-sku-override package=\"com.sony.product2.app\"/>\n"
+                        + "</config>\n";
+
+        final File folder1 = createTempSubfolder("folder1");
+        createTempFile(folder1, "permissionFile1.xml", disable_in_sku);
+
+        final File folder2 = createTempSubfolder("folder2");
+        createTempFile(folder2, "permissionFile2.xml", enable_in_sku_override);
+
+        readPermissions(folder1, /* Grant all permission flags */ ~0);
+        readPermissions(folder2, /* Grant all permission flags */ ~0);
+
+        final ArraySet<String> blocklist = mSysConfig.getDisabledUntilUsedPreinstalledCarrierApps();
+
+        assertThat(blocklist).contains("com.sony.product1.app");
+        assertThat(blocklist).doesNotContain("com.sony.product2.app");
+    }
+
     private void parseSharedLibraries(String contents) throws IOException {
         File folder = createTempSubfolder("permissions_folder");
         createTempFile(folder, "permissions.xml", contents);
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
index 5852af7..d20f73d 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
@@ -506,9 +506,9 @@
         assertThat(client0.getProfile().getInUseFrontendHandles())
                 .isEqualTo(new HashSet<Long>(Arrays.asList(infos[0].handle)));
 
-        // setResourceHolderRetain sets mResourceHolderRetain to true to allow the Resource Holder
-        // (client0) to maintain ownership such as requester will not get the resources.
-        client1.getProfile().setResourceHolderRetain(true);
+        // setResourceOwnershipRetention sets mResourceOwnerRetention to true to allow the Resource
+        // Holder (client0) to maintain ownership such as requester will not get the resources.
+        client1.getProfile().setResourceOwnershipRetention(true);
 
         request = tunerFrontendRequest(client1.getId() /*clientId*/, FrontendSettings.TYPE_DVBT);
         assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendHandle))
@@ -520,10 +520,10 @@
                 .isEqualTo(client0.getId());
         assertThat(client0.isReclaimed()).isFalse();
 
-        // setResourceHolderRetain sets mResourceHolderRetain to false to allow the Resource
+        // setResourceOwnershipRetention sets mResourceOwnerRetention to false to allow the Resource
         // Challenger (client1) to acquire the resource and Resource Holder loses ownership of the
         // resources.
-        client1.getProfile().setResourceHolderRetain(false);
+        client1.getProfile().setResourceOwnershipRetention(false);
 
         assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendHandle))
                 .isTrue();
@@ -645,9 +645,9 @@
                 .isEqualTo(new HashSet<Integer>(Arrays.asList(client0.getId())));
         assertThat(mTunerResourceManagerService.getCasResource(1).isFullyUsed()).isTrue();
 
-        // setResourceHolderRetain sets mResourceHolderRetain to true to allow the Resource Holder
-        // to maintain ownership such as requester (client1) will not get the resources.
-        client1.getProfile().setResourceHolderRetain(true);
+        // setResourceOwnershipRetention sets mResourceOwnerRetention to true to allow the Resource
+        // Holder to maintain ownership such as requester (client1) will not get the resources.
+        client1.getProfile().setResourceOwnershipRetention(true);
 
         request = casSessionRequest(client1.getId(), 1);
         assertThat(
@@ -663,10 +663,10 @@
         assertThat(mTunerResourceManagerService.getCasResource(1).isFullyUsed()).isTrue();
         assertThat(client0.isReclaimed()).isFalse();
 
-        // setResourceHolderRetain sets mResourceHolderRetain to false to allow the Resource
+        // setResourceOwnershipRetention sets mResourceOwnerRetention to false to allow the Resource
         // Challenger (client1) to acquire the resource and Resource Holder loses ownership of the
         // resources.
-        client1.getProfile().setResourceHolderRetain(false);
+        client1.getProfile().setResourceOwnershipRetention(false);
 
         assertThat(
                 mTunerResourceManagerService.requestCasSessionInternal(request, casSessionHandle))
@@ -759,9 +759,9 @@
                 .isEqualTo(new HashSet<Integer>(Arrays.asList(client0.getId())));
         assertThat(mTunerResourceManagerService.getCiCamResource(1).isFullyUsed()).isTrue();
 
-        // setResourceHolderRetain sets mResourceHolderRetain to true to allow the Resource Holder
-        // (client0) to maintain ownership such as requester will not get the resources.
-        client1.getProfile().setResourceHolderRetain(true);
+        // setResourceOwnershipRetention sets mResourceOwnerRetention to true to allow the Resource
+        // Holder (client0) to maintain ownership such as requester will not get the resources.
+        client1.getProfile().setResourceOwnershipRetention(true);
 
         request = tunerCiCamRequest(client1.getId(), 1);
         assertThat(mTunerResourceManagerService.requestCiCamInternal(request, ciCamHandle))
@@ -776,10 +776,10 @@
         assertThat(mTunerResourceManagerService.getCiCamResource(1).isFullyUsed()).isTrue();
         assertThat(client0.isReclaimed()).isFalse();
 
-        // setResourceHolderRetain sets mResourceHolderRetain to false to allow the Resource
+        // setResourceOwnershipRetention sets mResourceOwnerRetention to false to allow the Resource
         // Challenger (client1) to acquire the resource and Resource Holder loses ownership of the
         // resources.
-        client1.getProfile().setResourceHolderRetain(false);
+        client1.getProfile().setResourceOwnershipRetention(false);
 
         assertThat(mTunerResourceManagerService.requestCiCamInternal(request, ciCamHandle))
                 .isTrue();
@@ -927,9 +927,9 @@
         assertThat(client0.getProfile().getInUseLnbHandles())
                 .isEqualTo(new HashSet<Long>(Arrays.asList(lnbHandles[0])));
 
-        // setResourceHolderRetain sets mResourceHolderRetain to true to allow the Resource Holder
-        // (client0) to maintain ownership such as requester will not get the resources.
-        client1.getProfile().setResourceHolderRetain(true);
+        // setResourceOwnershipRetention sets mResourceOwnerRetention to true to allow the Resource
+        // Holder (client0) to maintain ownership such as requester will not get the resources.
+        client1.getProfile().setResourceOwnershipRetention(true);
 
         request = new TunerLnbRequest();
         request.clientId = client1.getId();
@@ -942,10 +942,10 @@
         assertThat(client0.isReclaimed()).isFalse();
         assertThat(client1.getProfile().getInUseLnbHandles().size()).isEqualTo(0);
 
-        // setResourceHolderRetain sets mResourceHolderRetain to false to allow the Resource
+        // setResourceOwnershipRetention sets mResourceOwnerRetention to false to allow the Resource
         // Challenger (client1) to acquire the resource and Resource Holder loses ownership of the
         // resources.
-        client1.getProfile().setResourceHolderRetain(false);
+        client1.getProfile().setResourceOwnershipRetention(false);
 
         assertThat(mTunerResourceManagerService.requestLnbInternal(request, lnbHandle)).isTrue();
         assertThat(lnbHandle[0]).isEqualTo(lnbHandles[0]);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
index 6af6542..dd278fc 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
@@ -2170,6 +2170,174 @@
     }
 
     @Test
+    @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS})
+    public void testRemoveChildNotification_summaryForceGrouped() {
+        // Check that removing all child notifications from a group will trigger empty summary
+        // force grouping re-evaluation
+        final List<NotificationRecord> notificationList = new ArrayList<>();
+        final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
+        final String pkg = "package";
+        // Post summaries without children, below the force grouping limit
+        for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) {
+            NotificationRecord summary = getNotificationRecord(pkg, i + 42, String.valueOf(i + 42),
+                    UserHandle.SYSTEM, "testGrp " + i, true);
+            notificationList.add(summary);
+            mGroupHelper.onNotificationPostedWithDelay(summary, notificationList, summaryByGroup);
+        }
+        // Post a valid (full) group
+        final int summaryId = 4242;
+        final int numChildren = 3;
+        final ArrayList<NotificationRecord> childrenToRemove = new ArrayList<>();
+        NotificationRecord summary = getNotificationRecord(pkg, summaryId,
+                String.valueOf(summaryId), UserHandle.SYSTEM, "testGrp " + summaryId, true);
+        notificationList.add(summary);
+        summaryByGroup.put(summary.getGroupKey(), summary);
+        for (int i = 0; i < numChildren; i++) {
+            NotificationRecord child = getNotificationRecord(pkg, summaryId + 42,
+                    String.valueOf(i + 42), UserHandle.SYSTEM, "testGrp " + summaryId, false);
+            notificationList.add(child);
+            // schedule all children for removal
+            childrenToRemove.add(child);
+        }
+        mGroupHelper.onNotificationPostedWithDelay(summary, notificationList, summaryByGroup);
+        verifyZeroInteractions(mCallback);
+
+        // Remove all child notifications from the valid group => summary without children
+        Mockito.reset(mCallback);
+        for (NotificationRecord r: childrenToRemove) {
+            notificationList.remove(r);
+            mGroupHelper.onNotificationRemoved(r, notificationList);
+        }
+        // Only call onGroupedNotificationRemovedWithDelay with the summary notification
+        mGroupHelper.onGroupedNotificationRemovedWithDelay(summary, notificationList,
+                summaryByGroup);
+
+        // Check that the summaries were force grouped
+        final String expectedGroupKey = GroupHelper.getFullAggregateGroupKey(pkg,
+                AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier());
+        verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
+                eq(expectedGroupKey), anyInt(), eq(getNotificationAttributes(BASE_FLAGS)));
+        verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(),
+                eq(expectedGroupKey), eq(true));
+        verify(mCallback, never()).removeAutoGroup(anyString());
+        verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
+        verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
+                any());
+    }
+
+    @Test
+    @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS})
+    public void testRemoveChildNotification_groupBecomesSingleton() {
+        // Check that removing child notifications from a group will trigger singleton force
+        // grouping re-evaluation
+        final List<NotificationRecord> notificationList = new ArrayList<>();
+        final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
+        final String pkg = "package";
+        // Post singleton groups, under forced group limit
+        for (int i = 0; i < AUTOGROUP_SINGLETONS_AT_COUNT - 1; i++) {
+            NotificationRecord summary = getNotificationRecord(pkg, i,
+                    String.valueOf(i), UserHandle.SYSTEM, "testGrp " + i, true);
+            notificationList.add(summary);
+            NotificationRecord child = getNotificationRecord(pkg, i + 42,
+                    String.valueOf(i + 42), UserHandle.SYSTEM, "testGrp " + i, false);
+            notificationList.add(child);
+            summaryByGroup.put(summary.getGroupKey(), summary);
+            mGroupHelper.onNotificationPostedWithDelay(child, notificationList, summaryByGroup);
+            mGroupHelper.onNotificationPostedWithDelay(summary, notificationList, summaryByGroup);
+        }
+        // Post a valid (full) group
+        final int summaryId = 4242;
+        final int numChildren = 3;
+        final ArrayList<NotificationRecord> childrenToRemove = new ArrayList<>();
+        NotificationRecord summary = getNotificationRecord(pkg, summaryId,
+                String.valueOf(summaryId), UserHandle.SYSTEM, "testGrp " + summaryId, true);
+        notificationList.add(summary);
+        summaryByGroup.put(summary.getGroupKey(), summary);
+        for (int i = 0; i < numChildren; i++) {
+            NotificationRecord child = getNotificationRecord(pkg, summaryId + 42,
+                    String.valueOf(i + 42), UserHandle.SYSTEM, "testGrp " + summaryId, false);
+            notificationList.add(child);
+
+            // schedule all children except one for removal
+            if (i < numChildren - 1) {
+                childrenToRemove.add(child);
+            }
+        }
+        mGroupHelper.onNotificationPostedWithDelay(summary, notificationList, summaryByGroup);
+        verifyZeroInteractions(mCallback);
+
+        // Remove some child notifications from the valid group, transform into a singleton group
+        Mockito.reset(mCallback);
+        for (NotificationRecord r: childrenToRemove) {
+            notificationList.remove(r);
+            mGroupHelper.onNotificationRemoved(r, notificationList);
+        }
+        // Only call onGroupedNotificationRemovedWithDelay with the summary notification
+        mGroupHelper.onGroupedNotificationRemovedWithDelay(summary, notificationList,
+                summaryByGroup);
+
+        // Check that the singleton groups were force grouped
+        final String expectedGroupKey = GroupHelper.getFullAggregateGroupKey(pkg,
+                AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier());
+        verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
+                eq(expectedGroupKey), anyInt(), eq(getNotificationAttributes(BASE_FLAGS)));
+        verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).addAutoGroup(anyString(),
+                eq(expectedGroupKey), eq(true));
+        verify(mCallback, never()).removeAutoGroup(anyString());
+        verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
+        verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
+                any());
+        verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).removeAppProvidedSummary(
+                anyString());
+    }
+
+    @Test
+    @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS})
+    public void testRemoveAllGroupNotifications_noForceGrouping() {
+        // Check that removing all notifications from a group will not trigger any force grouping
+        // re-evaluation
+        final List<NotificationRecord> notificationList = new ArrayList<>();
+        final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
+        final String pkg = "package";
+        // Post summaries without children, below the force grouping limit
+        for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) {
+            NotificationRecord summary = getNotificationRecord(pkg, i + 42, String.valueOf(i + 42),
+                    UserHandle.SYSTEM, "testGrp " + i, true);
+            notificationList.add(summary);
+            mGroupHelper.onNotificationPostedWithDelay(summary, notificationList, summaryByGroup);
+        }
+        // Post a valid (full) group
+        final int summaryId = 4242;
+        final int numChildren = 3;
+        final String groupToRemove = "testRemoveGrp";
+        NotificationRecord summary = getNotificationRecord(pkg, summaryId,
+                String.valueOf(summaryId), UserHandle.SYSTEM, groupToRemove + summaryId, true);
+        notificationList.add(summary);
+        summaryByGroup.put(summary.getGroupKey(), summary);
+        for (int i = 0; i < numChildren; i++) {
+            NotificationRecord child = getNotificationRecord(pkg, summaryId + 42,
+                    String.valueOf(i + 42), UserHandle.SYSTEM, groupToRemove + summaryId, false);
+            notificationList.add(child);
+        }
+        mGroupHelper.onNotificationPostedWithDelay(summary, notificationList, summaryByGroup);
+        verifyZeroInteractions(mCallback);
+
+        // Remove all child notifications from the valid group => summary without children
+        Mockito.reset(mCallback);
+        for (NotificationRecord r: notificationList) {
+            if (r.getGroupKey().contains(groupToRemove)) {
+                r.isCanceled = true;
+                mGroupHelper.onNotificationRemoved(r, notificationList);
+            }
+        }
+        // Only call onGroupedNotificationRemovedWithDelay with the summary notification
+        mGroupHelper.onGroupedNotificationRemovedWithDelay(summary, notificationList,
+                summaryByGroup);
+        // Check that nothing was force grouped
+        verifyZeroInteractions(mCallback);
+    }
+
+    @Test
     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
     public void testMoveAggregateGroups_updateChannel() {
         final String pkg = "package";
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index 9eddcc9..decbaac 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -60,8 +60,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.IntArray;
-import android.util.Log;
-import android.util.Slog;
 import android.util.Xml;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -729,4 +727,79 @@
         assertThat(mAssistants.getAllowedAdjustmentKeyTypes()).asList()
                 .containsExactly(TYPE_PROMOTION);
     }
+
+    @Test
+    @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+    public void testSetAssistantAdjustmentKeyTypeStateForPackage_allowsAndDenies() {
+        // Given that a package is allowed to have its type adjusted,
+        String allowedPackage = "allowed.package";
+        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty();
+        mAssistants.setTypeAdjustmentForPackageState(allowedPackage, true);
+
+        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty();
+        assertTrue(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPackage));
+
+        // Set type adjustment disallowed for this package
+        mAssistants.setTypeAdjustmentForPackageState(allowedPackage, false);
+
+        // Then the package is marked as denied
+        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
+                .containsExactly(allowedPackage);
+        assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPackage));
+
+        // Set type adjustment allowed again
+        mAssistants.setTypeAdjustmentForPackageState(allowedPackage, true);
+
+        // Then the package is marked as allowed again
+        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty();
+        assertTrue(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPackage));
+    }
+
+    @Test
+    @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+    public void testSetAssistantAdjustmentKeyTypeStateForPackage_deniesMultiple() {
+        // Given packages not allowed to have their type adjusted,
+        String deniedPkg1 = "denied.Pkg1";
+        String deniedPkg2 = "denied.Pkg2";
+        String deniedPkg3 = "denied.Pkg3";
+        // Set type adjustment disallowed for these packages
+        mAssistants.setTypeAdjustmentForPackageState(deniedPkg1, false);
+        mAssistants.setTypeAdjustmentForPackageState(deniedPkg2, false);
+        mAssistants.setTypeAdjustmentForPackageState(deniedPkg3, false);
+
+        // Then the packages are marked as denied
+        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
+                .containsExactlyElementsIn(List.of(deniedPkg1, deniedPkg2, deniedPkg3));
+        assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg1));
+        assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg2));
+        assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg3));
+
+        // And when we re-allow one of them,
+        mAssistants.setTypeAdjustmentForPackageState(deniedPkg2, true);
+
+        // Then the rest of the original packages are still marked as denied.
+        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
+                .containsExactlyElementsIn(List.of(deniedPkg1, deniedPkg3));
+        assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg1));
+        assertTrue(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg2));
+        assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg3));
+    }
+
+    @Test
+    @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+    public void testSetAssistantAdjustmentKeyTypeStateForPackage_readWriteXml() throws Exception {
+        mAssistants.loadDefaultsFromConfig(true);
+        String deniedPkg1 = "denied.Pkg1";
+        String allowedPkg2 = "allowed.Pkg2";
+        String deniedPkg3 = "denied.Pkg3";
+        // Set type adjustment disallowed or allowed for these packages
+        mAssistants.setTypeAdjustmentForPackageState(deniedPkg1, false);
+        mAssistants.setTypeAdjustmentForPackageState(allowedPkg2, true);
+        mAssistants.setTypeAdjustmentForPackageState(deniedPkg3, false);
+
+        writeXmlAndReload(USER_ALL);
+
+        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
+                .containsExactlyElementsIn(List.of(deniedPkg1, deniedPkg3));
+    }
 }
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
index b34b1fb..bf33333 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -907,10 +907,18 @@
         ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
         verify(mNm.mHandler, times(1)).post(runnableCaptor.capture());
         runnableCaptor.getValue().run();
-        ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor =
-                ArgumentCaptor.forClass(IStatusBarNotificationHolder.class);
-        verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any());
-        StatusBarNotification sbnResult = sbnCaptor.getValue().get();
+        StatusBarNotification sbnResult = null;
+        if (android.app.Flags.noSbnholder()) {
+            ArgumentCaptor<StatusBarNotification> sbnCaptor =
+                    ArgumentCaptor.forClass(StatusBarNotification.class);
+            verify(sysuiListener, times(1)).onNotificationPostedFull(sbnCaptor.capture(), any());
+            sbnResult = sbnCaptor.getValue();
+        } else {
+            ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor =
+                    ArgumentCaptor.forClass(IStatusBarNotificationHolder.class);
+            verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any());
+            sbnResult = sbnCaptor.getValue().get();
+        }
         assertThat(sbnResult.getNotification()
                 .extras.getCharSequence(Notification.EXTRA_TITLE).toString())
                 .isEqualTo("new title");
@@ -920,7 +928,7 @@
     }
 
     @Test
-    public void testListenerPostLifeimteExtension_postsToAppropriateListeners() throws Exception {
+    public void testListenerPostLifetimeExtension_postsToAppropriateListeners() throws Exception {
         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);
 
         // Create original notification, with FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY.
@@ -998,16 +1006,29 @@
             r.run();
         }
 
-        ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor =
-                ArgumentCaptor.forClass(IStatusBarNotificationHolder.class);
-        verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any());
-        StatusBarNotification sbnResult = sbnCaptor.getValue().get();
+        StatusBarNotification sbnResult = null;
+        if (android.app.Flags.noSbnholder()) {
+            ArgumentCaptor<StatusBarNotification> sbnCaptor =
+                    ArgumentCaptor.forClass(StatusBarNotification.class);
+            verify(sysuiListener, times(1)).onNotificationPostedFull(sbnCaptor.capture(), any());
+            sbnResult = sbnCaptor.getValue();
+        } else {
+            ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor =
+                    ArgumentCaptor.forClass(IStatusBarNotificationHolder.class);
+            verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any());
+            sbnResult = sbnCaptor.getValue().get();
+        }
         assertThat(sbnResult.getNotification()
                 .extras.getCharSequence(Notification.EXTRA_TITLE).toString())
                 .isEqualTo("new title");
 
-        verify(otherListener1, times(1)).onNotificationPosted(any(), any());
-        verify(otherListener2, times(1)).onNotificationPosted(any(), any());
+        if (android.app.Flags.noSbnholder()) {
+            verify(otherListener1, times(1)).onNotificationPostedFull(any(), any());
+            verify(otherListener2, times(1)).onNotificationPostedFull(any(), any());
+        } else {
+            verify(otherListener1, times(1)).onNotificationPosted(any(), any());
+            verify(otherListener2, times(1)).onNotificationPosted(any(), any());
+        }
     }
 
     @Test
@@ -1083,16 +1104,29 @@
             r.run();
         }
 
-        ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor =
-                ArgumentCaptor.forClass(IStatusBarNotificationHolder.class);
-        verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any());
-        StatusBarNotification sbnResult = sbnCaptor.getValue().get();
+        StatusBarNotification sbnResult = null;
+        if (android.app.Flags.noSbnholder()) {
+            ArgumentCaptor<StatusBarNotification> sbnCaptor =
+                    ArgumentCaptor.forClass(StatusBarNotification.class);
+            verify(sysuiListener, times(1)).onNotificationPostedFull(sbnCaptor.capture(), any());
+            sbnResult = sbnCaptor.getValue();
+        } else {
+            ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor =
+                    ArgumentCaptor.forClass(IStatusBarNotificationHolder.class);
+            verify(sysuiListener, times(1)).onNotificationPosted(sbnCaptor.capture(), any());
+            sbnResult = sbnCaptor.getValue().get();
+        }
         assertThat(sbnResult.getNotification()
                 .extras.getCharSequence(Notification.EXTRA_TITLE).toString())
                 .isEqualTo("new title");
 
-        verify(otherListener1, times(1)).onNotificationPosted(any(), any());
-        verify(otherListener2, times(1)).onNotificationPosted(any(), any());
+        if (android.app.Flags.noSbnholder()) {
+            verify(otherListener1, times(1)).onNotificationPostedFull(any(), any());
+            verify(otherListener2, times(1)).onNotificationPostedFull(any(), any());
+        } else {
+            verify(otherListener1, times(1)).onNotificationPosted(any(), any());
+            verify(otherListener2, times(1)).onNotificationPosted(any(), any());
+        }
     }
 
     /**
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 30af4ea..90bf1d3 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -232,7 +232,6 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.LauncherApps;
 import android.content.pm.ModuleInfo;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ParceledListSlice;
@@ -337,12 +336,12 @@
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
-import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
-import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
-
 import com.google.android.collect.Lists;
 import com.google.common.collect.ImmutableList;
 
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -361,9 +360,6 @@
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
-import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
-import platform.test.runner.parameterized.Parameters;
-
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
@@ -378,6 +374,9 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.function.Consumer;
 
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
 @SmallTest
 @RunWith(ParameterizedAndroidJunit4.class)
 @RunWithLooper
@@ -3094,6 +3093,92 @@
     }
 
     @Test
+    @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
+            android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
+    public void testScheduleGroupHelperWithDelay_onChildNotificationCanceled() throws Exception {
+        // Post summary + 2 child notification
+        final String originalGroupName = "originalGroup";
+        final int summaryId = 0;
+        final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel,
+                summaryId + 1, originalGroupName, false);
+        mService.addNotification(r1);
+        final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel,
+                summaryId + 2, originalGroupName, false);
+        mService.addNotification(r2);
+        final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel,
+                summaryId, originalGroupName, true);
+        mService.addNotification(summary);
+        final String originalGroupKey = summary.getGroupKey();
+        assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary);
+
+        // Cancel the child notifications
+        mBinderService.cancelNotificationWithTag(r1.getSbn().getPackageName(),
+                r1.getSbn().getPackageName(), r1.getSbn().getTag(),
+                r1.getSbn().getId(), r1.getSbn().getUserId());
+        waitForIdle();
+
+        mBinderService.cancelNotificationWithTag(r2.getSbn().getPackageName(),
+                r2.getSbn().getPackageName(), r2.getSbn().getTag(),
+                r2.getSbn().getId(), r2.getSbn().getUserId());
+        waitForIdle();
+
+        mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME);
+        waitForIdle();
+
+        // Check that onGroupedNotificationRemovedWithDelay was called only once
+        verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r1), any());
+        verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r2), any());
+        verify(mGroupHelper, times(1)).onGroupedNotificationRemovedWithDelay(eq(summary), any(),
+                any());
+    }
+
+    @Test
+    @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
+            android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
+    public void testCleanupScheduleGroupHelperWithDelay_onAllNotificationCanceled()
+            throws Exception {
+        // Post summary + 2 child notification
+        final String originalGroupName = "originalGroup";
+        final int summaryId = 0;
+        final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel,
+                summaryId + 1, originalGroupName, false);
+        mService.addNotification(r1);
+        final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel,
+                summaryId + 2, originalGroupName, false);
+        mService.addNotification(r2);
+        final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel,
+                summaryId, originalGroupName, true);
+        mService.addNotification(summary);
+        final String originalGroupKey = summary.getGroupKey();
+        assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary);
+
+        // Cancel all notifications: children + summary
+        mBinderService.cancelNotificationWithTag(r1.getSbn().getPackageName(),
+                r1.getSbn().getPackageName(), r1.getSbn().getTag(),
+                r1.getSbn().getId(), r1.getSbn().getUserId());
+        waitForIdle();
+
+        mBinderService.cancelNotificationWithTag(r2.getSbn().getPackageName(),
+                r2.getSbn().getPackageName(), r2.getSbn().getTag(),
+                r2.getSbn().getId(), r2.getSbn().getUserId());
+        waitForIdle();
+
+        mBinderService.cancelNotificationWithTag(summary.getSbn().getPackageName(),
+                summary.getSbn().getPackageName(), summary.getSbn().getTag(),
+                summary.getSbn().getId(), summary.getSbn().getUserId());
+        waitForIdle();
+
+        mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME);
+        waitForIdle();
+
+        // Check that onGroupedNotificationRemovedWithDelay was never called: summary was canceled
+        verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r1), any());
+        verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r2), any());
+        verify(mGroupHelper, times(1)).onNotificationRemoved(eq(summary), any());
+        verify(mGroupHelper, never()).onGroupedNotificationRemovedWithDelay(any(), any(), any());
+    }
+
+    @Test
     public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
         when(mAmi.applyForegroundServiceNotification(
                 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
@@ -6799,10 +6884,16 @@
     public void testReadPolicyXml_backupRestoreLogging() throws Exception {
         BackupRestoreEventLogger logger = mock(BackupRestoreEventLogger.class);
 
+        if (ActivityManager.getCurrentUser() != UserHandle.USER_SYSTEM) {
+            // By default, the ZenModeHelper only has a configuration for the system user.
+            // If the current user is not the system user, the user must be updated.
+            mService.mZenModeHelper.onUserSwitched(ActivityManager.getCurrentUser());
+        }
         UserInfo ui = new UserInfo(ActivityManager.getCurrentUser(), "Clone", UserInfo.FLAG_FULL);
         ui.userType = USER_TYPE_FULL_SYSTEM;
         when(mUmInternal.getUserInfo(ActivityManager.getCurrentUser())).thenReturn(ui);
-        when(mPermissionHelper.getNotificationPermissionValues(0)).thenReturn(new ArrayMap<>());
+        when(mPermissionHelper.getNotificationPermissionValues(ActivityManager.getCurrentUser()))
+                .thenReturn(new ArrayMap<>());
         TypedXmlSerializer serializer = Xml.newFastSerializer();
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
@@ -7534,6 +7625,7 @@
         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
+        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
 
         // Set up notifications that will be adjusted
         final NotificationRecord r1 = spy(generateNotificationRecord(
@@ -8845,8 +8937,8 @@
 
     @Test
     public void testAreBubblesEnabled_false() throws Exception {
-        Settings.Secure.putInt(mContext.getContentResolver(),
-                Settings.Secure.NOTIFICATION_BUBBLES, 0);
+        Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                Settings.Secure.NOTIFICATION_BUBBLES, 0, UserHandle.getUserId(mUid));
         mService.mPreferencesHelper.updateBubblesEnabled();
         assertFalse(mBinderService.areBubblesEnabled(UserHandle.getUserHandleForUid(mUid)));
     }
@@ -13224,6 +13316,7 @@
         when(mPermissionHelper.hasPermission(UID_N_MR1)).thenReturn(false);
         when(mPermissionHelper.hasPermission(UID_P)).thenReturn(true);
 
+        enableInteractAcrossUsers();
         assertThat(mBinderService.getPackagesBypassingDnd(UserHandle.getUserId(UID_P)).getList())
                 .containsExactly(new ZenBypassingApp(PKG_P, false));
     }
@@ -17142,6 +17235,7 @@
                 NotificationManagerService.WorkerHandler.class);
         mService.setHandler(handler);
         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
+        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
 
         Bundle signals = new Bundle();
         signals.putInt(KEY_TYPE, TYPE_NEWS);
@@ -17176,6 +17270,42 @@
     }
 
     @Test
+    @EnableFlags({android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION,
+            android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
+    public void testApplyAdjustment_keyTypeForDisallowedPackage_DoesNotApply() throws Exception {
+        final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+        mService.addNotification(r);
+        NotificationManagerService.WorkerHandler handler = mock(
+                NotificationManagerService.WorkerHandler.class);
+        mService.setHandler(handler);
+        when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
+        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
+
+        Bundle signals = new Bundle();
+        signals.putInt(KEY_TYPE, TYPE_NEWS);
+        Adjustment adjustment = new Adjustment(
+                r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
+        when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
+        mBinderService.applyAdjustmentFromAssistant(null, adjustment);
+
+        waitForIdle();
+
+        r.applyAdjustments();
+
+        assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
+
+        // When we block adjustments for this package
+        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(false);
+
+        signals.putInt(KEY_TYPE, TYPE_PROMOTION);
+        mBinderService.applyAdjustmentFromAssistant(null, adjustment);
+        waitForIdle();
+        r.applyAdjustments();
+        // Then the adjustment is not applied.
+        assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
+    }
+
+    @Test
     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
     public void testSetCanBePromoted_granted() throws Exception {
         // qualifying posted notification
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SystemZenRulesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SystemZenRulesTest.java
index 4d82c3c..949c5e2 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SystemZenRulesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SystemZenRulesTest.java
@@ -69,6 +69,8 @@
                 R.string.zen_mode_trigger_summary_range_symbol_combination, "%1$s-%2$s");
         mContext.getOrCreateTestableResources().addOverride(
                 R.string.zen_mode_trigger_summary_divider_text, ",");
+        mContext.getOrCreateTestableResources().addOverride(
+                R.string.zen_mode_trigger_summary_combined, "%1$s,%2$s");
     }
 
     @Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index bf61d06..09da015 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -7363,6 +7363,20 @@
         verify(callback, never()).onZenModeChanged();
     }
 
+    @Test
+    @EnableFlags(FLAG_MODES_MULTIUSER)
+    public void getNotificationPolicy_fromUserWithoutZenConfig_returnsDefaultPolicy() {
+        // Set a custom policy for the current user to double check we return a default one below.
+        mZenModeHelper.setNotificationPolicy(UserHandle.CURRENT, new Policy(0, 0, 0), ORIGIN_SYSTEM,
+                SYSTEM_UID);
+
+        Policy ghostPolicy = mZenModeHelper.getNotificationPolicy(UserHandle.of(5552368));
+
+        assertThat(ghostPolicy).isNotNull();
+        assertThat(ZenAdapters.notificationPolicyToZenPolicy(ghostPolicy))
+                .isEqualTo(mZenModeHelper.getDefaultZenPolicy());
+    }
+
     private static void addZenRule(ZenModeConfig config, String id, String ownerPkg, int zenMode,
             @Nullable ZenPolicy zenPolicy) {
         ZenRule rule = new ZenRule();
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
index 23ee893..da1c1ae 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -449,6 +449,18 @@
         }
     }
 
+    @Test
+    public void shouldIgnoreVibration_withoutAudioManager_allowsAllVibrations() {
+        mVibrationSettings = new VibrationSettings(mContextSpy,
+                new Handler(mTestLooper.getLooper()), mVibrationConfigMock);
+        mVibrationSettings.onSystemReady(mPackageManagerInternalMock,
+                mPowerManagerInternalMock, mActivityManagerMock, mVirtualDeviceManagerInternalMock,
+                /* audioManager= */ null);
+
+        for (int usage : ALL_USAGES) {
+            assertVibrationNotIgnoredForUsage(usage);
+        }
+    }
 
     @Test
     public void shouldIgnoreVibration_vibrateOnDisabled_ignoresUsagesNotAccessibility() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
index d5ed048..1d138e4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
@@ -249,6 +249,18 @@
     }
 
     @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    public void testShouldApplyCameraCompatFreeformTreatment_enabledByShellCommand_returnsTrue() {
+        runTestScenario((robot) -> {
+            robot.activity().createActivityWithComponentInNewTask();
+
+            robot.setCameraCompatTreatmentEnabledViaShellCommand(true);
+
+            robot.checkShouldApplyFreeformTreatmentForCameraCompat(true);
+        });
+    }
+
+    @Test
     @EnableCompatChanges({OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA,
             OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA,
             OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
@@ -350,6 +362,11 @@
             spyOn(displayContent.mAppCompatCameraPolicy);
         }
 
+        void setCameraCompatTreatmentEnabledViaShellCommand(boolean enabled) {
+            activity().top().mWmService.mAppCompatConfiguration
+                    .setIsCameraCompatFreeformWindowingTreatmentEnabled(enabled);
+        }
+
         void checkShouldRefreshActivityForCameraCompat(boolean expected) {
             Assert.assertEquals(getAppCompatCameraOverrides()
                     .shouldRefreshActivityForCameraCompat(), expected);
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index d6be915..40da9ea 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -66,6 +66,7 @@
 import android.window.BackAnimationAdapter;
 import android.window.BackMotionEvent;
 import android.window.BackNavigationInfo;
+import android.window.IBackAnimationHandoffHandler;
 import android.window.IOnBackInvokedCallback;
 import android.window.OnBackInvokedCallback;
 import android.window.OnBackInvokedCallbackInfo;
@@ -780,6 +781,10 @@
             @Override
             public void setTriggerBack(boolean triggerBack) {
             }
+
+            @Override
+            public void setHandoffHandler(IBackAnimationHandoffHandler unused) {
+            }
         };
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/CameraStateMonitorTests.java b/services/tests/wmtests/src/com/android/server/wm/CameraStateMonitorTests.java
index ad80f82..4810c7f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/CameraStateMonitorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/CameraStateMonitorTests.java
@@ -22,6 +22,8 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyLong;
@@ -137,6 +139,14 @@
     }
 
     @Test
+    public void testOnCameraOpened_listenerAdded_cameraRegistersAsOpenedDuringTheCallback() {
+        mCameraStateMonitor.addCameraStateListener(mListener);
+        mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+        assertTrue(mListener.mIsCameraOpened);
+    }
+
+    @Test
     public void testOnCameraOpened_cameraClosed_notifyCameraClosed() {
         mCameraStateMonitor.addCameraStateListener(mListener);
         // Listener returns true on `onCameraOpened`.
@@ -144,10 +154,21 @@
 
         mCameraAvailabilityCallback.onCameraClosed(CAMERA_ID_1);
 
+        assertEquals(1, mListener.mCheckCanCloseCounter);
         assertEquals(1, mListener.mOnCameraClosedCounter);
     }
 
     @Test
+    public void testOnCameraOpenedAndClosed_cameraRegistersAsClosedDuringTheCallback() {
+        mCameraStateMonitor.addCameraStateListener(mListener);
+        // Listener returns true on `onCameraOpened`.
+        mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+        mCameraAvailabilityCallback.onCameraClosed(CAMERA_ID_1);
+        assertFalse(mListener.mIsCameraOpened);
+    }
+
+    @Test
     public void testOnCameraOpened_listenerCannotCloseYet_notifyCameraClosedAgain() {
         mCameraStateMonitor.addCameraStateListener(mListenerCannotClose);
         // Listener returns true on `onCameraOpened`.
@@ -155,7 +176,8 @@
 
         mCameraAvailabilityCallback.onCameraClosed(CAMERA_ID_1);
 
-        assertEquals(2, mListenerCannotClose.mOnCameraClosedCounter);
+        assertEquals(2, mListenerCannotClose.mCheckCanCloseCounter);
+        assertEquals(1, mListenerCannotClose.mOnCameraClosedCounter);
     }
 
     @Test
@@ -197,39 +219,49 @@
             CameraStateMonitor.CameraCompatStateListener {
 
         int mOnCameraOpenedCounter = 0;
+        int mCheckCanCloseCounter = 0;
         int mOnCameraClosedCounter = 0;
 
-        private boolean mOnCameraClosedReturnValue = true;
+        boolean mIsCameraOpened;
+
+        private boolean mCheckCanCloseReturnValue = true;
 
         /**
-         * @param simulateUnsuccessfulCloseOnce When false, returns `true` on every
-         *                                      `onCameraClosed`. When true, returns `false` on the
-         *                                      first `onCameraClosed` callback, and `true on the
+         * @param simulateCannotCloseOnce When false, returns `true` on every
+         *                                      `checkCanClose`. When true, returns `false` on the
+         *                                      first `checkCanClose` callback, and `true on the
          *                                      subsequent calls. This fake implementation tests the
          *                                      retry mechanism in {@link CameraStateMonitor}.
          */
-        FakeCameraCompatStateListener(boolean simulateUnsuccessfulCloseOnce) {
-            mOnCameraClosedReturnValue = !simulateUnsuccessfulCloseOnce;
+        FakeCameraCompatStateListener(boolean simulateCannotCloseOnce) {
+            mCheckCanCloseReturnValue = !simulateCannotCloseOnce;
         }
 
         @Override
-        public void onCameraOpened(@NonNull ActivityRecord cameraActivity,
-                @NonNull String cameraId) {
+        public void onCameraOpened(@NonNull ActivityRecord cameraActivity) {
             mOnCameraOpenedCounter++;
+            mIsCameraOpened = mCameraStateMonitor.isCameraRunningForActivity(cameraActivity);
         }
 
         @Override
-        public boolean onCameraClosed(@NonNull String cameraId) {
-            mOnCameraClosedCounter++;
-            boolean returnValue = mOnCameraClosedReturnValue;
+        public boolean canCameraBeClosed(@NonNull String cameraId) {
+            mCheckCanCloseCounter++;
+            final boolean returnValue = mCheckCanCloseReturnValue;
             // If false, return false only the first time, so it doesn't fall in the infinite retry
             // loop.
-            mOnCameraClosedReturnValue = true;
+            mCheckCanCloseReturnValue = true;
             return returnValue;
         }
 
+        @Override
+        public void onCameraClosed() {
+            mOnCameraClosedCounter++;
+            mIsCameraOpened = mCameraStateMonitor.isCameraRunningForActivity(mActivity);
+        }
+
         void resetCounters() {
             mOnCameraOpenedCounter = 0;
+            mCheckCanCloseCounter = 0;
             mOnCameraClosedCounter = 0;
         }
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index c51261f..76b994d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -49,6 +49,7 @@
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.media.projection.StopReason;
 import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
 import android.view.ContentRecordingSession;
@@ -213,7 +214,7 @@
         mContentRecorder.setContentRecordingSession(session);
         mContentRecorder.updateRecording();
         assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
-        verify(mMediaProjectionManagerWrapper).stopActiveProjection();
+        verify(mMediaProjectionManagerWrapper).stopActiveProjection(StopReason.STOP_ERROR);
     }
 
     @Test
@@ -225,7 +226,7 @@
         mContentRecorder.setContentRecordingSession(invalidTaskSession);
         mContentRecorder.updateRecording();
         assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
-        verify(mMediaProjectionManagerWrapper).stopActiveProjection();
+        verify(mMediaProjectionManagerWrapper).stopActiveProjection(StopReason.STOP_ERROR);
     }
 
     @Test
@@ -310,8 +311,7 @@
                 mVirtualDisplayContent.getConfiguration().orientation, WINDOWING_MODE_FULLSCREEN);
 
         // No resize is issued, only the initial transformations when we started recording.
-        verify(mTransaction).setPosition(eq(mRecordedSurface), anyFloat(),
-                anyFloat());
+        verify(mTransaction).setPosition(eq(mRecordedSurface), anyFloat(), anyFloat());
         verify(mTransaction).setMatrix(eq(mRecordedSurface), anyFloat(), anyFloat(),
                 anyFloat(), anyFloat());
     }
@@ -386,19 +386,18 @@
 
         // WHEN a configuration change arrives, and the recorded content is a different size.
         Configuration configuration = mTask.getConfiguration();
-        configuration.windowConfiguration.setBounds(new Rect(0, 0, recordedWidth, recordedHeight));
-        configuration.windowConfiguration.setAppBounds(
-                new Rect(0, 0, recordedWidth, recordedHeight));
+        Rect newBounds = new Rect(0, 0, recordedWidth, recordedHeight);
+        configuration.windowConfiguration.setBounds(newBounds);
+        configuration.windowConfiguration.setAppBounds(newBounds);
         mTask.onConfigurationChanged(configuration);
         assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
 
         // THEN content in the captured DisplayArea is scaled to fit the surface size.
-        verify(mTransaction, atLeastOnce()).setMatrix(eq(mRecordedSurface), anyFloat(), eq(0f),
-                eq(0f),
-                anyFloat());
+        verify(mTransaction, atLeastOnce()).setMatrix(
+                eq(mRecordedSurface), anyFloat(), eq(0f), eq(0f), anyFloat());
         // THEN the resize callback is notified.
-        verify(mMediaProjectionManagerWrapper).notifyActiveProjectionCapturedContentResized(
-                recordedWidth, recordedHeight);
+        verify(mMediaProjectionManagerWrapper).notifyCaptureBoundsChanged(
+                mTaskSession.getContentToRecord(), mTaskSession.getTargetUid(), newBounds);
     }
 
     @Test
@@ -649,7 +648,7 @@
 
         mTask.removeImmediately();
 
-        verify(mMediaProjectionManagerWrapper).stopActiveProjection();
+        verify(mMediaProjectionManagerWrapper).stopActiveProjection(StopReason.STOP_TARGET_REMOVED);
     }
 
     @Test
@@ -684,8 +683,8 @@
         int xInset = (mSurfaceSize.x - scaledWidth) / 2;
         verify(mTransaction, atLeastOnce()).setPosition(mRecordedSurface, xInset, 0);
         // THEN the resize callback is notified.
-        verify(mMediaProjectionManagerWrapper).notifyActiveProjectionCapturedContentResized(
-                displayAreaBounds.width(), displayAreaBounds.height());
+        verify(mMediaProjectionManagerWrapper).notifyCaptureBoundsChanged(
+                mDisplaySession.getContentToRecord(), mDisplaySession.getTargetUid(),  displayAreaBounds);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DeferredDisplayUpdaterDiffTest.java b/services/tests/wmtests/src/com/android/server/wm/DeferredDisplayUpdaterDiffTest.java
index c9c31df..a0f4ae7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DeferredDisplayUpdaterDiffTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DeferredDisplayUpdaterDiffTest.java
@@ -239,6 +239,9 @@
         } else if (type.equals(FrameRateCategoryRate.class)) {
             field.set(first, new FrameRateCategoryRate(16666667, 11111111));
             field.set(second, new FrameRateCategoryRate(11111111, 8333333));
+        } else if (type.isArray() && type.getComponentType().equals(float.class)) {
+            field.set(first, new float[]{60.0f});
+            field.set(second, new float[]{120.0f});
         } else {
             throw new IllegalArgumentException("Field " + field
                     + " is not supported by this test, please add implementation of setting "
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java
index c8fc482..6397334 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java
@@ -20,16 +20,19 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.verify;
 
 import android.platform.test.annotations.Presubmit;
 import android.view.Surface;
@@ -54,6 +57,7 @@
 
     private DisplayRotationImmersiveAppCompatPolicy mPolicy;
 
+    private DisplayRotation mMockDisplayRotation;
     private AppCompatConfiguration mMockAppCompatConfiguration;
     private ActivityRecord mMockActivityRecord;
     private Task mMockTask;
@@ -98,6 +102,7 @@
         when(mockDisplayRotation.isLandscapeOrSeascape(Surface.ROTATION_90)).thenReturn(true);
         when(mockDisplayRotation.isLandscapeOrSeascape(Surface.ROTATION_180)).thenReturn(false);
         when(mockDisplayRotation.isLandscapeOrSeascape(Surface.ROTATION_270)).thenReturn(true);
+        mMockDisplayRotation = mockDisplayRotation;
 
         return mockDisplayRotation;
     }
@@ -196,6 +201,24 @@
     }
 
     @Test
+    public void testDeferOrientationUpdate() {
+        assertFalse(mPolicy.deferOrientationUpdate());
+
+        doReturn(SCREEN_ORIENTATION_UNSPECIFIED).when(mMockDisplayRotation).getLastOrientation();
+        final WindowOrientationListener orientationListener = mock(WindowOrientationListener.class);
+        doReturn(Surface.ROTATION_90).when(orientationListener).getProposedRotation();
+        doReturn(orientationListener).when(mMockDisplayRotation).getOrientationListener();
+        spyOn(mDisplayContent.mTransitionController);
+        doReturn(true).when(mDisplayContent.mTransitionController)
+                .hasTransientLaunch(mDisplayContent);
+
+        assertTrue(mPolicy.deferOrientationUpdate());
+        mDisplayContent.mTransitionController.mStateValidators.getFirst().run();
+
+        verify(mWm).updateRotation(false, false);
+    }
+
+    @Test
     public void testRotationChoiceEnforcedOnly_nullTopRunningActivity_lockNotEnforced() {
         when(mDisplayContent.topRunningActivity()).thenReturn(null);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java b/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java
index a0c5b54..c016c5e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java
@@ -69,7 +69,9 @@
     private static final FrameRateVote FRAME_RATE_VOTE_60_PREFERRED =
             new FrameRateVote(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT,
                     SurfaceControl.FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN);
-
+    private static final float HI_REFRESH_RATE = 90;
+    private static final float MID_REFRESH_RATE = 70;
+    private static final float LOW_REFRESH_RATE = 60;
     WindowState createWindow(String name) {
         WindowState window = createWindow(null, TYPE_APPLICATION, name);
         when(window.mWmService.mDisplayManagerInternal.getRefreshRateSwitchingType())
@@ -82,14 +84,16 @@
         DisplayInfo di = new DisplayInfo(mDisplayInfo);
         Mode defaultMode = di.getDefaultMode();
         Mode hiMode = new Mode(1,
-                defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), 90);
+                defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), HI_REFRESH_RATE);
         Mode midMode = new Mode(2,
-                defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), 70);
+                defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), MID_REFRESH_RATE);
         Mode lowMode = new Mode(LOW_MODE_ID,
-                defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), 60);
+                defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), LOW_REFRESH_RATE);
 
         di.supportedModes = new Mode[] { hiMode, midMode };
         di.appsSupportedModes = new Mode[] { hiMode, midMode, lowMode };
+        di.supportedRefreshRates = new float[] {HI_REFRESH_RATE, MID_REFRESH_RATE,
+                LOW_REFRESH_RATE};
         di.defaultModeId = 1;
         mRefreshRatePolicy = new RefreshRatePolicy(mWm, di, mDenylist);
         when(mDisplayPolicy.getRefreshRatePolicy()).thenReturn(mRefreshRatePolicy);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 7ed8283..aa99250 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -434,6 +434,7 @@
     @Test
     public void testAddTaskCompatibleWindowingMode_withFreeformAndFullscreen_expectRemove() {
         Task task1 = createTaskBuilder(".Task1")
+                .setTaskId(1)
                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
                 .build();
         doReturn(WINDOWING_MODE_FREEFORM).when(task1).getWindowingMode();
@@ -452,6 +453,10 @@
         assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
         assertThat(mCallbacksRecorder.mRemoved).hasSize(1);
         assertThat(mCallbacksRecorder.mRemoved).contains(task1);
+
+        TaskChangeNotificationController controller =
+                mAtm.getTaskChangeNotificationController();
+        verify(controller, times(1)).notifyRecentTaskRemovedForAddTask(task1.mTaskId);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
index cc38f02..73e5f58 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
@@ -101,6 +101,8 @@
                 defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), LOW_REFRESH_RATE);
         mDisplayInfo.supportedModes = new Mode[] { hiMode, midMode };
         mDisplayInfo.appsSupportedModes = new Mode[] { hiMode, midMode, lowMode };
+        mDisplayInfo.supportedRefreshRates = new float[] {HI_REFRESH_RATE, MID_REFRESH_RATE,
+                LOW_REFRESH_RATE};
         mDisplayInfo.defaultModeId = HI_MODE_ID;
         mPolicy = new RefreshRatePolicy(mWm, mDisplayInfo, mDenylist);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
index 791b5b5..a92fe3a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
@@ -162,6 +162,10 @@
             verifySecureExceptionThrown(activityOptions, taskSupervisor);
 
             activityOptions = ActivityOptions.makeBasic();
+            activityOptions.setTaskAlwaysOnTop(true);
+            verifySecureExceptionThrown(activityOptions, taskSupervisor);
+
+            activityOptions = ActivityOptions.makeBasic();
             activityOptions.setLaunchDisplayId(DEFAULT_DISPLAY);
             verifySecureExceptionThrown(activityOptions, taskSupervisor);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 41f1e23..87db6c0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -4863,7 +4863,7 @@
 
     @Test
     @EnableFlags(Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
-    public void testCameraCompatAspectRatio_defualtAspectRatioAppliedWhenGreater() {
+    public void testCameraCompatAspectRatio_defaultAspectRatioAppliedWhenGreater() {
         // Needed to create camera compat policy in DisplayContent.
         allowDesktopMode();
         // Create display that has all stable insets and does not rotate.
@@ -4899,6 +4899,8 @@
         prepareLimitedBounds(mActivity, maxAspect, minAspect,
                 ActivityInfo.SCREEN_ORIENTATION_NOSENSOR, true /* isUnresizable */);
 
+        assertTrue(ActivityRecord.canBeUniversalResizeable(mActivity.info.applicationInfo,
+                mWm, true /* isLargeScreen */, false /* forActivity */));
         assertTrue(mActivity.isUniversalResizeable());
         assertTrue(mActivity.isResizeable());
         assertFalse(mActivity.shouldCreateAppCompatDisplayInsets());
@@ -4917,7 +4919,8 @@
         assertEquals(minAspect, aspectRatioPolicy.getMinAspectRatio(), 0 /* delta */);
 
         // User override can still take effect.
-        doReturn(true).when(aspectRatioOverrides).shouldApplyUserMinAspectRatioOverride();
+        doReturn(USER_MIN_ASPECT_RATIO_3_2).when(aspectRatioOverrides)
+                .getUserMinAspectRatioOverrideCode();
         assertFalse(mActivity.isResizeable());
         assertEquals(maxAspect, aspectRatioPolicy.getMaxAspectRatio(), 0 /* delta */);
         assertNotEquals(SCREEN_ORIENTATION_UNSPECIFIED, mActivity.getOverrideOrientation());
@@ -4928,6 +4931,7 @@
         spyOn(pm);
         final PackageManager.Property property = new PackageManager.Property("propertyName",
                 true /* value */, name.getPackageName(), name.getClassName());
+        // Activity level.
         try {
             doReturn(property).when(pm).getPropertyAsUser(
                     WindowManager.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY,
@@ -4938,6 +4942,21 @@
         final ActivityRecord optOutActivity = new ActivityBuilder(mAtm)
                 .setComponent(name).setTask(mTask).build();
         assertFalse(optOutActivity.isUniversalResizeable());
+
+        // Application level.
+        try {
+            doReturn(property).when(pm).getProperty(
+                    WindowManager.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY,
+                    name.getPackageName());
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+        final ActivityRecord optOutAppActivity = new ActivityBuilder(mAtm)
+                .setComponent(getUniqueComponentName(mContext.getPackageName()))
+                .setTask(mTask).build();
+        assertFalse(optOutAppActivity.isUniversalResizeable());
+        assertFalse(ActivityRecord.canBeUniversalResizeable(mActivity.info.applicationInfo,
+                mWm, true /* isLargeScreen */, false /* forActivity */));
     }
 
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 8bbba1b..a425401 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -42,7 +42,6 @@
 import static android.view.flags.Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION;
 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
@@ -85,7 +84,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.platform.test.annotations.Presubmit;
-import android.platform.test.annotations.RequiresFlagsDisabled;
 import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -97,7 +95,6 @@
 import android.view.InputDevice;
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
-import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.View;
 import android.view.WindowInsets;
@@ -1192,55 +1189,6 @@
                 argThat(h -> (h.inputConfig & InputConfig.SENSITIVE_FOR_PRIVACY) != 0));
     }
 
-    @RequiresFlagsDisabled(Flags.FLAG_ALWAYS_DRAW_MAGNIFICATION_FULLSCREEN_BORDER)
-    @Test
-    public void testDrawMagnifiedViewport() {
-        final int displayId = mDisplayContent.mDisplayId;
-        // Use real surface, so ViewportWindow's BlastBufferQueue can be created.
-        final ArrayList<SurfaceControl> surfaceControls = new ArrayList<>();
-        mWm.mSurfaceControlFactory = () -> new SurfaceControl.Builder() {
-            @Override
-            public SurfaceControl build() {
-                final SurfaceControl sc = super.build();
-                surfaceControls.add(sc);
-                return sc;
-            }
-        };
-        mWm.mAccessibilityController.setMagnificationCallbacks(displayId,
-                mock(WindowManagerInternal.MagnificationCallbacks.class));
-        final boolean[] lockCanvasInWmLock = { false };
-        final Surface surface = mWm.mAccessibilityController.forceShowMagnifierSurface(displayId);
-        spyOn(surface);
-        doAnswer(invocationOnMock -> {
-            lockCanvasInWmLock[0] |= Thread.holdsLock(mWm.mGlobalLock);
-            invocationOnMock.callRealMethod();
-            return null;
-        }).when(surface).lockCanvas(any());
-        mWm.mAccessibilityController
-                .recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded(displayId);
-        waitUntilHandlersIdle();
-        try {
-            verify(surface).lockCanvas(any());
-
-            clearInvocations(surface);
-            // Invalidate and redraw.
-            mWm.mAccessibilityController.onDisplaySizeChanged(mDisplayContent);
-            mWm.mAccessibilityController
-                    .recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded(displayId);
-            // Turn off magnification to release surface.
-            mWm.mAccessibilityController.setMagnificationCallbacks(displayId, null);
-            waitUntilHandlersIdle();
-            // lockCanvas must not be called after releasing.
-            verify(surface, never()).lockCanvas(any());
-            verify(surface).release();
-            assertFalse(lockCanvasInWmLock[0]);
-        } finally {
-            for (int i = surfaceControls.size() - 1; i >= 0; --i) {
-                surfaceControls.get(i).release();
-            }
-        }
-    }
-
     @Test
     public void testRequestKeyboardShortcuts_noWindow() {
         doNothing().when(mWm.mContext).enforceCallingOrSelfPermission(anyString(), anyString());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 757c358..78e6cbf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -1027,7 +1027,8 @@
             }
 
             @Override
-            public void setImeInputTargetRequestedVisibility(boolean visible) {
+            public void setImeInputTargetRequestedVisibility(boolean visible,
+                    @NonNull ImeTracker.Token statsToken) {
             }
         };
     }
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 5ef0fe3..d976f5ba 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -337,7 +337,7 @@
                                       deviceAddress, hasOutput, hasInput,
                                       isInputHeadset, isOutputHeadset, isDock);
             alsaDevice.setDeviceNameAndDescription(
-                      cardRec.getCardName(), cardRec.getCardDescription());
+                    usbDevice.getProductName(), cardRec.getCardDescription());
             if (IS_MULTI_MODE) {
                 deselectCurrentDevice(alsaDevice.getInputDeviceType());
                 deselectCurrentDevice(alsaDevice.getOutputDeviceType());
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 9c961c1..ad5d42a 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -8825,9 +8825,6 @@
      *          {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION} or doesn't support given
      *          authType.
      */
-    // TODO(b/73660190): This should probably require MODIFY_PHONE_STATE, not
-    // READ_PRIVILEGED_PHONE_STATE. It certainly shouldn't reference the permission in Javadoc since
-    // it's not public API.
     @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public String getIccAuthentication(int appType, @AuthType int authType, String data) {
         return getIccAuthentication(getSubId(), appType, authType, data);
@@ -19602,4 +19599,37 @@
             throw ex.rethrowAsRuntimeException();
         }
     }
+
+    /**
+     * Returns carrier id maps to the passing CarrierIdentifier.
+     * To recognize a carrier (including MVNO) as a first-class identity,
+     * Android assigns each carrier with a canonical integer a.k.a. carrier id.
+     * The carrier ID is an Android platform-wide identifier for a carrier.
+     * AOSP maintains carrier ID assignments in
+     * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/latest_carrier_id/carrier_list.textpb">here</a>
+     *
+     * @param carrierIdentifier {@link CarrierIdentifier}
+     *
+     * @return Carrier id. Return {@link #UNKNOWN_CARRIER_ID} if the carrier cannot be identified.
+     * @throws UnsupportedOperationException If the device does not have
+     *          {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}.
+     *
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_CARRIER_ID_FROM_CARRIER_IDENTIFIER)
+    @SystemApi
+    @WorkerThread
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public int getCarrierIdFromCarrierIdentifier(@NonNull CarrierIdentifier carrierIdentifier) {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                return service.getCarrierIdFromIdentifier(carrierIdentifier);
+            }
+        } catch (RemoteException ex) {
+            // This could happen if binder process crashes.
+        }
+        return UNKNOWN_CARRIER_ID;
+    }
 }
diff --git a/telephony/java/android/telephony/satellite/ISelectedNbIotSatelliteSubscriptionCallback.aidl b/telephony/java/android/telephony/satellite/ISelectedNbIotSatelliteSubscriptionCallback.aidl
new file mode 100644
index 0000000..178bb3c
--- /dev/null
+++ b/telephony/java/android/telephony/satellite/ISelectedNbIotSatelliteSubscriptionCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright 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.telephony.satellite;
+
+/**
+ * Interface for selected satellite subscription change callback.
+ *
+ * @hide
+ */
+oneway interface ISelectedNbIotSatelliteSubscriptionCallback {
+    /**
+     * Called when the selected satellite subscription has changed.
+     *
+     * @param selectedSubId The new satellite subscription id.
+     */
+    void onSelectedNbIotSatelliteSubscriptionChanged(in int selectedSubId);
+}
diff --git a/telephony/java/android/telephony/satellite/SatelliteInfo.java b/telephony/java/android/telephony/satellite/SatelliteInfo.java
index 7ff2318..1d5f613 100644
--- a/telephony/java/android/telephony/satellite/SatelliteInfo.java
+++ b/telephony/java/android/telephony/satellite/SatelliteInfo.java
@@ -17,7 +17,6 @@
 package android.telephony.satellite;
 
 import android.annotation.FlaggedApi;
-import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.ParcelUuid;
 import android.os.Parcelable;
@@ -47,10 +46,12 @@
     private UUID mId;
 
     /**
-     * Position information of a satellite.
+     * Position information of a geostationary satellite.
      * This includes the longitude and altitude of the satellite.
+     * If the SatellitePosition is invalid,
+     * longitudeDegree and altitudeKm will be represented as DOUBLE.NaN.
      */
-    @Nullable
+    @NonNull
     private SatellitePosition mPosition;
 
     /**
@@ -89,7 +90,7 @@
      * @param earfcnRanges      The list of {@link EarfcnRange} objects representing the EARFCN
      *                          ranges supported by the satellite.
      */
-    public SatelliteInfo(@NonNull UUID satelliteId, @Nullable SatellitePosition satellitePosition,
+    public SatelliteInfo(@NonNull UUID satelliteId, @NonNull SatellitePosition satellitePosition,
             @NonNull List<Integer> bandList, @NonNull List<EarfcnRange> earfcnRanges) {
         mId = satelliteId;
         mPosition = satellitePosition;
@@ -135,10 +136,9 @@
     /**
      * Returns the position of the satellite.
      *
-     * @return The {@link SatellitePosition} of the satellite, or {@code null} if the position is
-     * not available.
+     * @return The {@link SatellitePosition} of the satellite.
      */
-    @Nullable
+    @NonNull
     public SatellitePosition getSatellitePosition() {
         return mPosition;
     }
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 23203ed..b96b6c5 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -99,16 +99,18 @@
     private static final ConcurrentHashMap<SatelliteSupportedStateCallback,
             ISatelliteSupportedStateCallback> sSatelliteSupportedStateCallbackMap =
             new ConcurrentHashMap<>();
-
     private static final ConcurrentHashMap<SatelliteCommunicationAllowedStateCallback,
             ISatelliteCommunicationAllowedStateCallback>
             sSatelliteCommunicationAllowedStateCallbackMap =
             new ConcurrentHashMap<>();
-
     private static final ConcurrentHashMap<SatelliteDisallowedReasonsCallback,
             ISatelliteDisallowedReasonsCallback>
             sSatelliteDisallowedReasonsCallbackMap =
             new ConcurrentHashMap<>();
+    private static final ConcurrentHashMap<SelectedNbIotSatelliteSubscriptionCallback,
+            ISelectedNbIotSatelliteSubscriptionCallback>
+            sSelectedNbIotSatelliteSubscriptionCallbackMap =
+            new ConcurrentHashMap<>();
 
     private final int mSubId;
 
@@ -219,6 +221,14 @@
 
     /**
      * Bundle key to get the response from
+     * {@link #requestSessionStats(Executor, OutcomeReceiver)}.
+     * @hide
+     */
+
+    public static final String KEY_SESSION_STATS_V2 = "session_stats_v2";
+
+    /**
+     * Bundle key to get the response from
      * {@link #requestIsProvisioned(Executor, OutcomeReceiver)}.
      * @hide
      */
@@ -746,7 +756,7 @@
      * @hide
      */
     public static final String ACTION_SATELLITE_SUBSCRIBER_ID_LIST_CHANGED =
-            "android.telephony.action.ACTION_SATELLITE_SUBSCRIBER_ID_LIST_CHANGED";
+            "android.telephony.satellite.action.SATELLITE_SUBSCRIBER_ID_LIST_CHANGED";
 
 
     /**
@@ -757,7 +767,7 @@
      * @hide
      */
     public static final String ACTION_SATELLITE_START_NON_EMERGENCY_SESSION =
-            "android.telephony.action.ACTION_SATELLITE_START_NON_EMERGENCY_SESSION";
+            "android.telephony.satellite.action.SATELLITE_START_NON_EMERGENCY_SESSION";
     /**
      * Meta-data represents whether the application supports P2P SMS over carrier roaming satellite
      * which needs manual trigger to connect to satellite. The messaging applications that supports
@@ -2541,6 +2551,89 @@
     }
 
     /**
+     * Registers for selected satellite subscription changed event from the satellite service.
+     *
+     * @param executor The executor on which the callback will be called.
+     * @param callback The callback to handle the selected satellite subscription changed event.
+     *
+     * @throws SecurityException if the caller doesn't have required permission.
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+    @SatelliteResult public int registerForSelectedNbIotSatelliteSubscriptionChanged(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull SelectedNbIotSatelliteSubscriptionCallback callback) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                ISelectedNbIotSatelliteSubscriptionCallback internalCallback =
+                        new ISelectedNbIotSatelliteSubscriptionCallback.Stub() {
+                            @Override
+                            public void onSelectedNbIotSatelliteSubscriptionChanged(
+                                    int selectedSubId) {
+                                executor.execute(() -> Binder.withCleanCallingIdentity(
+                                        () -> callback.onSelectedNbIotSatelliteSubscriptionChanged(
+                                                selectedSubId)));
+                            }
+                        };
+                sSelectedNbIotSatelliteSubscriptionCallbackMap.put(callback, internalCallback);
+                return telephony.registerForSelectedNbIotSatelliteSubscriptionChanged(
+                        internalCallback);
+            } else {
+                throw new IllegalStateException("Telephony service is null.");
+            }
+        } catch (RemoteException ex) {
+            loge("registerForSelectedNbIotSatelliteSubscriptionChanged() RemoteException: " + ex);
+            ex.rethrowFromSystemServer();
+        }
+        return SATELLITE_RESULT_REQUEST_FAILED;
+    }
+
+    /**
+     * Unregisters for selected satellite subscription changed event from the satellite service. If
+     * callback was not registered before, the request will be ignored.
+     *
+     * @param callback The callback that was passed to {@link
+     *     #registerForSelectedNbIotSatelliteSubscriptionChanged(Executor,
+     *     SelectedNbIotSatelliteSubscriptionCallback)}.
+     *
+     * @throws SecurityException if the caller doesn't have required permission.
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+    public void unregisterForSelectedNbIotSatelliteSubscriptionChanged(
+            @NonNull SelectedNbIotSatelliteSubscriptionCallback callback) {
+        Objects.requireNonNull(callback);
+        ISelectedNbIotSatelliteSubscriptionCallback internalCallback =
+                sSelectedNbIotSatelliteSubscriptionCallbackMap.remove(callback);
+
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                if (internalCallback != null) {
+                    telephony.unregisterForSelectedNbIotSatelliteSubscriptionChanged(
+                            internalCallback);
+                } else {
+                    loge("unregisterForSelectedNbIotSatelliteSubscriptionChanged: " +
+                            "No internal callback.");
+                }
+            } else {
+                throw new IllegalStateException("Telephony service is null.");
+            }
+        } catch (RemoteException ex) {
+            loge("unregisterForSelectedNbIotSatelliteSubscriptionChanged() RemoteException: " +
+                    ex);
+            ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Inform whether the device is aligned with the satellite in both real and demo mode.
      *
      * In demo mode, framework will send datagram to modem only when device is aligned with
@@ -3383,21 +3476,33 @@
                     @Override
                     protected void onReceiveResult(int resultCode, Bundle resultData) {
                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
+                            SatelliteSessionStats stats;
                             if (resultData.containsKey(KEY_SESSION_STATS)) {
-                                SatelliteSessionStats stats =
-                                        resultData.getParcelable(KEY_SESSION_STATS,
-                                                SatelliteSessionStats.class);
-                                executor.execute(() -> Binder.withCleanCallingIdentity(() ->
-                                        callback.onResult(stats)));
+                                stats = resultData.getParcelable(KEY_SESSION_STATS,
+                                        SatelliteSessionStats.class);
+                                if (resultData.containsKey(KEY_SESSION_STATS_V2)) {
+                                    SatelliteSessionStats stats1 = resultData.getParcelable(
+                                            KEY_SESSION_STATS_V2, SatelliteSessionStats.class);
+                                    if (stats != null && stats1 != null) {
+                                        stats.setSatelliteSessionStats(
+                                                stats1.getSatelliteSessionStats());
+                                        executor.execute(() -> Binder.withCleanCallingIdentity(
+                                                () -> callback.onResult(stats)));
+                                        return;
+                                    }
+                                } else {
+                                    loge("KEY_SESSION_STATS_V2 does not exist.");
+                                }
                             } else {
                                 loge("KEY_SESSION_STATS does not exist.");
-                                executor.execute(() -> Binder.withCleanCallingIdentity(() ->
-                                        callback.onError(new SatelliteException(
-                                                SATELLITE_RESULT_REQUEST_FAILED))));
                             }
+                            executor.execute(() -> Binder.withCleanCallingIdentity(
+                                    () -> callback.onError(new SatelliteException(
+                                            SATELLITE_RESULT_REQUEST_FAILED))));
+
                         } else {
-                            executor.execute(() -> Binder.withCleanCallingIdentity(() ->
-                                    callback.onError(new SatelliteException(resultCode))));
+                            executor.execute(() -> Binder.withCleanCallingIdentity(
+                                    () -> callback.onError(new SatelliteException(resultCode))));
                         }
                     }
                 };
diff --git a/telephony/java/android/telephony/satellite/SatelliteSessionStats.java b/telephony/java/android/telephony/satellite/SatelliteSessionStats.java
index aabb058..1c59449 100644
--- a/telephony/java/android/telephony/satellite/SatelliteSessionStats.java
+++ b/telephony/java/android/telephony/satellite/SatelliteSessionStats.java
@@ -19,23 +19,38 @@
 import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Log;
 
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Objects;
 
 /**
  * SatelliteSessionStats is used to represent the usage stats of the satellite service.
+ *
  * @hide
  */
 public class SatelliteSessionStats implements Parcelable {
+
     private int mCountOfSuccessfulUserMessages;
     private int mCountOfUnsuccessfulUserMessages;
     private int mCountOfTimedOutUserMessagesWaitingForConnection;
     private int mCountOfTimedOutUserMessagesWaitingForAck;
     private int mCountOfUserMessagesInQueueToBeSent;
+    private long mLatencyOfSuccessfulUserMessages;
+
+    private Map<Integer, SatelliteSessionStats> datagramStats;
+    private long mMaxLatency;
+    private long mLastMessageLatency;
+
+    public SatelliteSessionStats() {
+        this.datagramStats = new HashMap<>();
+    }
 
     /**
      * SatelliteSessionStats constructor
-     * @param  builder Builder to create SatelliteSessionStats object/
+     *
+     * @param builder Builder to create SatelliteSessionStats object/
      */
     public SatelliteSessionStats(@NonNull Builder builder) {
         mCountOfSuccessfulUserMessages = builder.mCountOfSuccessfulUserMessages;
@@ -45,6 +60,7 @@
         mCountOfTimedOutUserMessagesWaitingForAck =
                 builder.mCountOfTimedOutUserMessagesWaitingForAck;
         mCountOfUserMessagesInQueueToBeSent = builder.mCountOfUserMessagesInQueueToBeSent;
+        mLatencyOfSuccessfulUserMessages = builder.mLatencyOfSuccessfulUserMessages;
     }
 
     private SatelliteSessionStats(Parcel in) {
@@ -63,6 +79,19 @@
         out.writeInt(mCountOfTimedOutUserMessagesWaitingForConnection);
         out.writeInt(mCountOfTimedOutUserMessagesWaitingForAck);
         out.writeInt(mCountOfUserMessagesInQueueToBeSent);
+        out.writeLong(mLatencyOfSuccessfulUserMessages);
+        out.writeLong(mMaxLatency);
+        out.writeLong(mLastMessageLatency);
+
+        if (datagramStats != null && !datagramStats.isEmpty()) {
+            out.writeInt(datagramStats.size());
+            for (Map.Entry<Integer, SatelliteSessionStats> entry : datagramStats.entrySet()) {
+                out.writeInt(entry.getKey());
+                out.writeParcelable(entry.getValue(), flags);
+            }
+        } else {
+            out.writeInt(0);
+        }
     }
 
     @NonNull
@@ -83,6 +112,40 @@
     @NonNull
     public String toString() {
         StringBuilder sb = new StringBuilder();
+        if (datagramStats != null) {
+            sb.append(" ====== SatelliteSessionStatsWrapper Info =============");
+            for (Map.Entry<Integer, SatelliteSessionStats> entry : datagramStats.entrySet()) {
+                Integer key = entry.getKey();
+                SatelliteSessionStats value = entry.getValue();
+                sb.append("\n");
+                sb.append("Key:");
+                sb.append(key);
+                sb.append(", SatelliteSessionStats:[");
+                value.getPrintableCounters(sb);
+                sb.append(",");
+                sb.append(" LatencyOfSuccessfulUserMessages:");
+                sb.append(value.mLatencyOfSuccessfulUserMessages);
+                sb.append(",");
+                sb.append(" mMaxLatency:");
+                sb.append(value.mMaxLatency);
+                sb.append(",");
+                sb.append(" mLastMessageLatency:");
+                sb.append(value.mLastMessageLatency);
+                sb.append("]");
+                sb.append("\n");
+            }
+            sb.append(" ============== ================== ===============");
+            sb.append("\n");
+            sb.append("\n");
+        } else {
+            sb.append("\n");
+            getPrintableCounters(sb);
+        }
+        sb.append("\n");
+        return sb.toString();
+    }
+
+    private void getPrintableCounters(StringBuilder sb) {
         sb.append("countOfSuccessfulUserMessages:");
         sb.append(mCountOfSuccessfulUserMessages);
         sb.append(",");
@@ -101,7 +164,6 @@
 
         sb.append("countOfUserMessagesInQueueToBeSent:");
         sb.append(mCountOfUserMessagesInQueueToBeSent);
-        return sb.toString();
     }
 
     @Override
@@ -110,49 +172,176 @@
         if (o == null || getClass() != o.getClass()) return false;
         SatelliteSessionStats that = (SatelliteSessionStats) o;
         return mCountOfSuccessfulUserMessages == that.mCountOfSuccessfulUserMessages
+                && mLatencyOfSuccessfulUserMessages == that.mLatencyOfSuccessfulUserMessages
                 && mCountOfUnsuccessfulUserMessages == that.mCountOfUnsuccessfulUserMessages
                 && mCountOfTimedOutUserMessagesWaitingForConnection
                 == that.mCountOfTimedOutUserMessagesWaitingForConnection
                 && mCountOfTimedOutUserMessagesWaitingForAck
                 == that.mCountOfTimedOutUserMessagesWaitingForAck
-                && mCountOfUserMessagesInQueueToBeSent
-                == that.mCountOfUserMessagesInQueueToBeSent;
+                && mCountOfUserMessagesInQueueToBeSent == that.mCountOfUserMessagesInQueueToBeSent;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mCountOfSuccessfulUserMessages, mCountOfUnsuccessfulUserMessages,
-                mCountOfTimedOutUserMessagesWaitingForConnection,
-                mCountOfTimedOutUserMessagesWaitingForAck,
-                mCountOfUserMessagesInQueueToBeSent);
+        return Objects.hash(mCountOfSuccessfulUserMessages, mLatencyOfSuccessfulUserMessages,
+                mCountOfUnsuccessfulUserMessages, mCountOfTimedOutUserMessagesWaitingForConnection,
+                mCountOfTimedOutUserMessagesWaitingForAck, mCountOfUserMessagesInQueueToBeSent);
     }
 
     public int getCountOfSuccessfulUserMessages() {
         return mCountOfSuccessfulUserMessages;
     }
 
+    public void incrementSuccessfulUserMessageCount() {
+        mCountOfSuccessfulUserMessages++;
+    }
+
     public int getCountOfUnsuccessfulUserMessages() {
         return mCountOfUnsuccessfulUserMessages;
     }
 
+    public void incrementUnsuccessfulUserMessageCount() {
+        mCountOfUnsuccessfulUserMessages++;
+    }
+
     public int getCountOfTimedOutUserMessagesWaitingForConnection() {
         return mCountOfTimedOutUserMessagesWaitingForConnection;
     }
 
+    public void incrementTimedOutUserMessagesWaitingForConnection() {
+        mCountOfTimedOutUserMessagesWaitingForConnection++;
+    }
+
     public int getCountOfTimedOutUserMessagesWaitingForAck() {
         return mCountOfTimedOutUserMessagesWaitingForAck;
     }
 
+    public void incrementTimedOutUserMessagesWaitingForAck() {
+        mCountOfTimedOutUserMessagesWaitingForAck++;
+    }
+
     public int getCountOfUserMessagesInQueueToBeSent() {
         return mCountOfUserMessagesInQueueToBeSent;
     }
 
+    public long getLatencyOfAllSuccessfulUserMessages() {
+        return mLatencyOfSuccessfulUserMessages;
+    }
+
+    public void updateLatencyOfAllSuccessfulUserMessages(long messageLatency) {
+        mLatencyOfSuccessfulUserMessages += messageLatency;
+    }
+
+    public void recordSuccessfulOutgoingDatagramStats(
+            @SatelliteManager.DatagramType int datagramType, long latency) {
+        try {
+            datagramStats.putIfAbsent(datagramType, new SatelliteSessionStats.Builder().build());
+            SatelliteSessionStats data = datagramStats.get(datagramType);
+            data.incrementSuccessfulUserMessageCount();
+            if (data.mMaxLatency < latency) {
+                data.mMaxLatency = latency;
+            }
+            data.mLastMessageLatency = latency;
+            data.updateLatencyOfAllSuccessfulUserMessages(latency);
+        } catch (Exception e) {
+            Log.e("SatelliteSessionStats",
+                    "Error while recordSuccessfulOutgoingDatagramStats: " + e.getMessage());
+        }
+    }
+
+    public int getCountOfSuccessfulOutgoingDatagram(
+            @SatelliteManager.DatagramType int datagramType) {
+        SatelliteSessionStats data = datagramStats.getOrDefault(datagramType,
+                new SatelliteSessionStats());
+        return data.getCountOfSuccessfulUserMessages();
+    }
+
+    public long getMaxLatency() {
+        return this.mMaxLatency;
+    }
+
+    public Long getLatencyOfAllSuccessfulUserMessages(
+            @SatelliteManager.DatagramType int datagramType) {
+        SatelliteSessionStats data = datagramStats.getOrDefault(datagramType,
+                new SatelliteSessionStats());
+        return data.getLatencyOfAllSuccessfulUserMessages();
+    }
+
+
+    public long getLastMessageLatency() {
+        return this.mLastMessageLatency;
+    }
+
+    public void addCountOfUnsuccessfulUserMessages(@SatelliteManager.DatagramType int datagramType,
+            @SatelliteManager.SatelliteResult int resultCode) {
+        try {
+            datagramStats.putIfAbsent(datagramType, new SatelliteSessionStats.Builder().build());
+            SatelliteSessionStats data = datagramStats.get(datagramType);
+            data.incrementUnsuccessfulUserMessageCount();
+            if (resultCode == SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE) {
+                data.incrementTimedOutUserMessagesWaitingForConnection();
+            } else if (resultCode == SatelliteManager.SATELLITE_RESULT_MODEM_TIMEOUT) {
+                data.incrementTimedOutUserMessagesWaitingForAck();
+            }
+        } catch (Exception e) {
+            Log.e("SatelliteSessionStats",
+                    "Error while addCountOfUnsuccessfulUserMessages: " + e.getMessage());
+        }
+    }
+
+    public int getCountOfUnsuccessfulUserMessages(@SatelliteManager.DatagramType int datagramType) {
+        SatelliteSessionStats data = datagramStats.get(datagramType);
+        return data.getCountOfUnsuccessfulUserMessages();
+    }
+
+    public int getCountOfTimedOutUserMessagesWaitingForConnection(
+            @SatelliteManager.DatagramType int datagramType) {
+        SatelliteSessionStats data = datagramStats.get(datagramType);
+        return data.getCountOfTimedOutUserMessagesWaitingForConnection();
+    }
+
+    public int getCountOfTimedOutUserMessagesWaitingForAck(
+            @SatelliteManager.DatagramType int datagramType) {
+        SatelliteSessionStats data = datagramStats.get(datagramType);
+        return data.getCountOfTimedOutUserMessagesWaitingForAck();
+    }
+
+    public int getCountOfUserMessagesInQueueToBeSent(
+            @SatelliteManager.DatagramType int datagramType) {
+        SatelliteSessionStats data = datagramStats.get(datagramType);
+        return data.getCountOfUserMessagesInQueueToBeSent();
+    }
+
+    public void clear() {
+        datagramStats.clear();
+    }
+
+    public Map<Integer, SatelliteSessionStats> getSatelliteSessionStats() {
+        return datagramStats;
+    }
+
+    public void setSatelliteSessionStats(Map<Integer, SatelliteSessionStats> sessionStats) {
+        this.datagramStats = sessionStats;
+    }
+
     private void readFromParcel(Parcel in) {
         mCountOfSuccessfulUserMessages = in.readInt();
         mCountOfUnsuccessfulUserMessages = in.readInt();
         mCountOfTimedOutUserMessagesWaitingForConnection = in.readInt();
         mCountOfTimedOutUserMessagesWaitingForAck = in.readInt();
         mCountOfUserMessagesInQueueToBeSent = in.readInt();
+        mLatencyOfSuccessfulUserMessages = in.readLong();
+        mMaxLatency = in.readLong();
+        mLastMessageLatency = in.readLong();
+
+        int size = in.readInt();
+        datagramStats = new HashMap<>();
+        for (int i = 0; i < size; i++) {
+            Integer key = in.readInt();
+            SatelliteSessionStats value = in.readParcelable(
+                    SatelliteSessionStats.class.getClassLoader());
+            datagramStats.put(key, value);
+        }
     }
 
     /**
@@ -164,7 +353,10 @@
         private int mCountOfTimedOutUserMessagesWaitingForConnection;
         private int mCountOfTimedOutUserMessagesWaitingForAck;
         private int mCountOfUserMessagesInQueueToBeSent;
+        private long mLatencyOfSuccessfulUserMessages;
 
+        private long mMaxLatency;
+        private long mLastMessageLatency;
         /**
          * Sets countOfSuccessfulUserMessages value of {@link SatelliteSessionStats}
          * and then returns the Builder class.
@@ -215,10 +407,28 @@
             return this;
         }
 
+        @NonNull
+        public Builder setLatencyOfSuccessfulUserMessages(long latency) {
+            mLatencyOfSuccessfulUserMessages = latency;
+            return this;
+        }
+
+        @NonNull
+        public Builder setMaxLatency(long maxLatency) {
+            mMaxLatency = maxLatency;
+            return this;
+        }
+
+        @NonNull
+        public Builder setLastLatency(long lastLatency) {
+            mLastMessageLatency = lastLatency;
+            return this;
+        }
+
         /** Returns SatelliteSessionStats object. */
         @NonNull
         public SatelliteSessionStats build() {
             return new SatelliteSessionStats(this);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/satellite/SelectedNbIotSatelliteSubscriptionCallback.java b/telephony/java/android/telephony/satellite/SelectedNbIotSatelliteSubscriptionCallback.java
new file mode 100644
index 0000000..d896554
--- /dev/null
+++ b/telephony/java/android/telephony/satellite/SelectedNbIotSatelliteSubscriptionCallback.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.satellite;
+
+/**
+ * A callback class for selected satellite subscription changed events.
+ *
+ * @hide
+ */
+public interface SelectedNbIotSatelliteSubscriptionCallback {
+    /**
+     * Called when the selected satellite subscription has changed.
+     *
+     * @param selectedSubId The new satellite subscription id.
+     */
+    void onSelectedNbIotSatelliteSubscriptionChanged(int selectedSubId);
+}
diff --git a/telephony/java/android/telephony/satellite/SystemSelectionSpecifier.java b/telephony/java/android/telephony/satellite/SystemSelectionSpecifier.java
index 8a5e7f2..c2ac44f 100644
--- a/telephony/java/android/telephony/satellite/SystemSelectionSpecifier.java
+++ b/telephony/java/android/telephony/satellite/SystemSelectionSpecifier.java
@@ -17,11 +17,13 @@
 package android.telephony.satellite;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
 import android.util.IntArray;
 
+import java.util.Arrays;
 import java.util.Objects;
 
 /**
@@ -39,16 +41,26 @@
      * The radio channels to scan as defined in 3GPP TS 25.101 and 36.101.
      * Maximum length of the vector is 32.
      */
-    @NonNull private IntArray mEarfcs;
+    @NonNull private IntArray mEarfcns;
+
+    /* The list of satellites configured for the current location */
+    @Nullable
+    private SatelliteInfo[] mSatelliteInfos;
+
+    /* The list of tag IDs associated with the current location */
+    @Nullable private IntArray mTagIds;
 
     /**
      * @hide
      */
     public SystemSelectionSpecifier(@NonNull String mccmnc, @NonNull IntArray bands,
-            @NonNull IntArray earfcs) {
+            @NonNull IntArray earfcns, @Nullable SatelliteInfo[] satelliteInfos,
+            @Nullable IntArray tagIds) {
         mMccMnc = mccmnc;
         mBands = bands;
-        mEarfcs = earfcs;
+        mEarfcns = earfcns;
+        mSatelliteInfos = satelliteInfos;
+        mTagIds = tagIds;
     }
 
     private SystemSelectionSpecifier(Parcel in) {
@@ -74,10 +86,21 @@
             out.writeInt(0);
         }
 
-        if (mEarfcs != null && mEarfcs.size() > 0) {
-            out.writeInt(mEarfcs.size());
-            for (int i = 0; i < mEarfcs.size(); i++) {
-                out.writeInt(mEarfcs.get(i));
+        if (mEarfcns != null && mEarfcns.size() > 0) {
+            out.writeInt(mEarfcns.size());
+            for (int i = 0; i < mEarfcns.size(); i++) {
+                out.writeInt(mEarfcns.get(i));
+            }
+        } else {
+            out.writeInt(0);
+        }
+
+        out.writeTypedArray(mSatelliteInfos, flags);
+
+        if (mTagIds != null) {
+            out.writeInt(mTagIds.size());
+            for (int i = 0; i < mTagIds.size(); i++) {
+                out.writeInt(mTagIds.get(i));
             }
         } else {
             out.writeInt(0);
@@ -115,14 +138,35 @@
         }
 
         sb.append("earfcs:");
-        if (mEarfcs != null && mEarfcs.size() > 0) {
-            for (int i = 0; i < mEarfcs.size(); i++) {
-                sb.append(mEarfcs.get(i));
+        if (mEarfcns != null && mEarfcns.size() > 0) {
+            for (int i = 0; i < mEarfcns.size(); i++) {
+                sb.append(mEarfcns.get(i));
                 sb.append(",");
             }
         } else {
             sb.append("none");
         }
+
+        sb.append("mSatelliteInfos:");
+        if (mSatelliteInfos != null && mSatelliteInfos.length > 0) {
+            for (SatelliteInfo satelliteInfo : mSatelliteInfos) {
+                sb.append(satelliteInfo);
+                sb.append(",");
+            }
+        } else {
+            sb.append("none");
+        }
+
+        sb.append("mTagIds:");
+        if (mTagIds != null && mTagIds.size() > 0) {
+            for (int i = 0; i < mTagIds.size(); i++) {
+                sb.append(mTagIds.get(i));
+                sb.append(",");
+            }
+        } else {
+            sb.append("none");
+        }
+
         return sb.toString();
     }
 
@@ -133,12 +177,15 @@
         SystemSelectionSpecifier that = (SystemSelectionSpecifier) o;
         return Objects.equals(mMccMnc, that.mMccMnc)
                 && Objects.equals(mBands, that.mBands)
-                && Objects.equals(mEarfcs, that.mEarfcs);
+                && Objects.equals(mEarfcns, that.mEarfcns)
+                && (mSatelliteInfos == null ? that.mSatelliteInfos == null : Arrays.equals(
+                mSatelliteInfos, that.mSatelliteInfos))
+                && Objects.equals(mTagIds, that.mTagIds);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mMccMnc, mBands, mEarfcs);
+        return Objects.hash(mMccMnc, mBands, mEarfcns);
     }
 
     @NonNull public String getMccMnc() {
@@ -149,8 +196,18 @@
         return mBands;
     }
 
-    @NonNull public IntArray getEarfcs() {
-        return mEarfcs;
+    @NonNull public IntArray getEarfcns() {
+        return mEarfcns;
+    }
+
+    @NonNull
+    public SatelliteInfo[] getSatelliteInfos() {
+        return mSatelliteInfos;
+    }
+
+    @NonNull
+    public IntArray getTagIds() {
+        return mTagIds;
     }
 
     private void readFromParcel(Parcel in) {
@@ -164,11 +221,20 @@
             }
         }
 
-        mEarfcs = new IntArray();
-        int numEarfcs = in.readInt();
-        if (numEarfcs > 0) {
-            for (int i = 0; i < numEarfcs; i++) {
-                mEarfcs.add(in.readInt());
+        mEarfcns = new IntArray();
+        int numEarfcns = in.readInt();
+        if (numEarfcns > 0) {
+            for (int i = 0; i < numEarfcns; i++) {
+                mEarfcns.add(in.readInt());
+            }
+        }
+
+        mSatelliteInfos = in.createTypedArray(SatelliteInfo.CREATOR);
+
+        int numTagIds = in.readInt();
+        if (numTagIds > 0) {
+            for (int i = 0; i < numTagIds; i++) {
+                mTagIds.add(in.readInt());
             }
         }
     }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/telephony/java/android/telephony/satellite/stub/EarfcnRange.aidl
similarity index 60%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to telephony/java/android/telephony/satellite/stub/EarfcnRange.aidl
index 7d3d8b9..6e9d19e 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/telephony/java/android/telephony/satellite/stub/EarfcnRange.aidl
@@ -5,7 +5,7 @@
  * 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
+ *     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,
@@ -13,10 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.telephony.satellite.stub;
+
+/**
+ * @hide
+ */
+parcelable EarfcnRange {
+    /**
+     * The start frequency of the earfcn range and is inclusive in the range
+     */
+    int startEarfcn;
+
+    /**
+     * The end frequency of the earfcn range and is inclusive in the range.
+     */
+    int endEarfcn;
 }
diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteInfo.aidl b/telephony/java/android/telephony/satellite/stub/SatelliteInfo.aidl
new file mode 100644
index 0000000..312bd8f
--- /dev/null
+++ b/telephony/java/android/telephony/satellite/stub/SatelliteInfo.aidl
@@ -0,0 +1,52 @@
+/*
+ * 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.telephony.satellite.stub;
+
+import android.telephony.satellite.stub.UUID;
+import android.telephony.satellite.stub.SatellitePosition;
+import android.telephony.satellite.stub.EarfcnRange;
+
+/**
+ * @hide
+ */
+parcelable SatelliteInfo {
+    /**
+     * Unique identification number for the satellite.
+     * This ID is used to distinguish between different satellites in the network.
+     */
+    UUID id;
+
+    /**
+     * Position information of a geostationary satellite.
+     * This includes the longitude and altitude of the satellite.
+     * If the SatellitePosition is invalid,
+     * longitudeDegree and altitudeKm will be represented as DOUBLE.NaN.
+     */
+    SatellitePosition position;
+
+    /**
+     * The frequency bands to scan.
+     * Bands will be filled only if the whole band is needed.
+     * Maximum length of the vector is 8.
+     */
+    int[] bands;
+
+    /**
+     * The supported frequency ranges. Earfcn ranges and earfcns won't overlap.
+     */
+    EarfcnRange[] earfcnRanges;
+}
diff --git a/telephony/java/android/telephony/satellite/stub/SatellitePosition.aidl b/telephony/java/android/telephony/satellite/stub/SatellitePosition.aidl
new file mode 100644
index 0000000..e87b26c
--- /dev/null
+++ b/telephony/java/android/telephony/satellite/stub/SatellitePosition.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.telephony.satellite.stub;
+
+/**
+ * @hide
+ */
+parcelable SatellitePosition {
+    /**
+     * The longitude of the satellite in degrees, ranging from -180 to 180 degrees
+     */
+    double longitudeDegree;
+
+    /**
+     * The distance from the center of the earth to the satellite, measured in kilometers
+     */
+    double altitudeKm;
+}
diff --git a/telephony/java/android/telephony/satellite/stub/SystemSelectionSpecifier.aidl b/telephony/java/android/telephony/satellite/stub/SystemSelectionSpecifier.aidl
index 22240f6..3aff4cb 100644
--- a/telephony/java/android/telephony/satellite/stub/SystemSelectionSpecifier.aidl
+++ b/telephony/java/android/telephony/satellite/stub/SystemSelectionSpecifier.aidl
@@ -16,6 +16,8 @@
 
 package android.telephony.satellite.stub;
 
+import android.telephony.satellite.stub.SatelliteInfo;
+
 /**
  * {@hide}
  */
@@ -24,15 +26,26 @@
     String mMccMnc;
 
     /**
-     * The frequency bands to scan. Bands and earfcns won't overlap.
+     * The frequency bands to scan.
      * Bands will be filled only if the whole band is needed.
      * Maximum length of the vector is 8.
+     * The values are populated from the mBands array within the SatelliteInfo[] array, which is
+     * included in the SystemSelectionSpecifier, for backward compatibility.
      */
     int[] mBands;
 
     /**
      * The radio channels to scan as defined in 3GPP TS 25.101 and 36.101.
+     * The values are populated from the earfcns defined in the EarfcnRange[] array inside
+     * SatelliteInfo[], which is included in the SystemSelectionSpecifier, for backward
+     * compatibility.
      * Maximum length of the vector is 32.
      */
     int[] mEarfcs;
+
+    /* The list of satellites configured for the current location */
+    SatelliteInfo[] satelliteInfos;
+
+    /* The list of tag IDs associated with the current location */
+    int[] tagIds;
 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/telephony/java/android/telephony/satellite/stub/UUID.aidl
similarity index 64%
copy from ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
copy to telephony/java/android/telephony/satellite/stub/UUID.aidl
index 7d3d8b9..004a507 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ b/telephony/java/android/telephony/satellite/stub/UUID.aidl
@@ -5,7 +5,7 @@
  * 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
+ *     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,
@@ -13,10 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.platform.test.ravenwood;
 
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
-    public RavenwoodConfigState(RavenwoodConfig config) {
-    }
+package android.telephony.satellite.stub;
+
+/**
+ * @hide
+ */
+parcelable UUID {
+    /*
+     * The most significant 64 bits of this UUID.
+     */
+    long mostSigBits;
+
+    /*
+     * The least significant 64 bits of this UUID.
+     */
+    long leastSigBits;
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index d22e9fa..131f46b 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -76,6 +76,7 @@
 import android.telephony.satellite.ISatelliteProvisionStateCallback;
 import android.telephony.satellite.ISatelliteSupportedStateCallback;
 import android.telephony.satellite.ISatelliteModemStateCallback;
+import android.telephony.satellite.ISelectedNbIotSatelliteSubscriptionCallback;
 import android.telephony.satellite.NtnSignalStrength;
 import android.telephony.satellite.SatelliteCapabilities;
 import android.telephony.satellite.SatelliteDatagram;
@@ -3030,6 +3031,30 @@
     void requestSelectedNbIotSatelliteSubscriptionId(in ResultReceiver receiver);
 
     /**
+     * Registers for selected satellite subscription changed event from the satellite service.
+     *
+     * @param executor The executor on which the callback will be called.
+     * @param callback The callback to handle the satellite subscription changed event.
+     */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+            + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+    int registerForSelectedNbIotSatelliteSubscriptionChanged(
+            in ISelectedNbIotSatelliteSubscriptionCallback callback);
+
+    /**
+     * Unregisters for selected satellite subscription changed event from the satellite service. If
+     * callback was not registered before, the request will be ignored.
+     *
+     * @param callback The callback that was passed to {@link
+     *     #registerForSelectedNbIotSatelliteSubscriptionChanged(Executor,
+     *     SelectedNbIotSatelliteSubscriptionCallback)}.
+     */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+            + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+    void unregisterForSelectedNbIotSatelliteSubscriptionChanged(
+            in ISelectedNbIotSatelliteSubscriptionCallback callback);
+
+    /**
      * Inform whether the device is aligned with the satellite in both real and demo mode.
      *
      * @param isAligned {@true} Device is aligned with the satellite.
@@ -3143,7 +3168,7 @@
      */
     boolean setSatelliteAccessControlOverlayConfigs(in boolean reset, in boolean isAllowed,
             in String s2CellFile, in long locationFreshDurationNanos,
-            in List<String> satelliteCountryCodes);
+            in List<String> satelliteCountryCodes, String satelliteAccessConfigurationFile);
 
     /**
      * This API can be used in only testing to override oem-enabled satellite provision status.
@@ -3519,4 +3544,15 @@
     * @hide
     */
     void setNtnSmsSupported(boolean ntnSmsSupported);
+
+    /**
+     * Returns carrier id maps to the passing {@link CarrierIdentifier}.
+     *
+     * @param {@link CarrierIdentifier}.
+     *
+     * @return carrier id from passing {@link CarrierIdentifier} or {@link #UNKNOWN_CARRIER_ID}
+     * if the carrier cannot be identified
+     * @hide
+     */
+    int getCarrierIdFromIdentifier(in CarrierIdentifier carrierIdentifier);
 }
diff --git a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java
index bfce3d2..6d818d7 100644
--- a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java
+++ b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java
@@ -159,7 +159,7 @@
 
     private static BatteryUsageStats buildBatteryUsageStats() {
         final BatteryUsageStats.Builder builder =
-                new BatteryUsageStats.Builder(new String[]{"FOO"}, true, false, false, false, 0)
+                new BatteryUsageStats.Builder(new String[]{"FOO"}, false, false, false, 0)
                         .setBatteryCapacity(4000)
                         .setDischargePercentage(20)
                         .setDischargedPowerRange(1000, 2000)
@@ -182,8 +182,7 @@
                             .setTimeInProcessStateMs(UidBatteryConsumer.STATE_BACKGROUND, i * 1000);
             for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT;
                     componentId++) {
-                consumerBuilder.addConsumedPower(componentId, componentId * 123.0,
-                        BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+                consumerBuilder.addConsumedPower(componentId, componentId * 123.0);
                 consumerBuilder.addUsageDurationMillis(componentId, componentId * 1000);
             }
 
diff --git a/tests/BinaryTransparencyHostTest/Android.bp b/tests/BinaryTransparencyHostTest/Android.bp
index e14e5fe..1c8386a 100644
--- a/tests/BinaryTransparencyHostTest/Android.bp
+++ b/tests/BinaryTransparencyHostTest/Android.bp
@@ -31,6 +31,8 @@
     ],
     static_libs: [
         "truth",
+        "flag-junit-host",
+        "android.app.flags-aconfig-java-host",
     ],
     device_common_data: [
         ":BinaryTransparencyTestApp",
diff --git a/tests/BinaryTransparencyHostTest/src/android/transparency/test/BinaryTransparencyHostTest.java b/tests/BinaryTransparencyHostTest/src/android/transparency/test/BinaryTransparencyHostTest.java
index 6e5f08a..6d8dbcb 100644
--- a/tests/BinaryTransparencyHostTest/src/android/transparency/test/BinaryTransparencyHostTest.java
+++ b/tests/BinaryTransparencyHostTest/src/android/transparency/test/BinaryTransparencyHostTest.java
@@ -24,6 +24,9 @@
 
 import android.platform.test.annotations.LargeTest;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.host.HostFlagsValueProvider;
 
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil.CLog;
@@ -34,6 +37,7 @@
 import com.android.tradefed.util.CommandStatus;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -49,6 +53,10 @@
     /** Waiting time for the job to be scheduled */
     private static final int JOB_CREATION_MAX_SECONDS = 30;
 
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            HostFlagsValueProvider.createCheckFlagsRule(this::getDevice);
+
     @Before
     public void setUp() throws Exception {
         cancelPendingJob();
@@ -123,6 +131,7 @@
         }
     }
 
+    @RequiresFlagsDisabled(android.app.Flags.FLAG_BACKGROUND_INSTALL_CONTROL_CALLBACK_API)
     @Test
     public void testPreloadUpdateTriggersJobScheduling() throws Exception {
         try {
diff --git a/tests/FlickerTests/ActivityEmbedding/AndroidTestTemplate.xml b/tests/FlickerTests/ActivityEmbedding/AndroidTestTemplate.xml
index 8b65efd..685ae9a 100644
--- a/tests/FlickerTests/ActivityEmbedding/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/ActivityEmbedding/AndroidTestTemplate.xml
@@ -45,6 +45,8 @@
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="test-user-token" value="%TEST_USER%"/>
         <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
+        <!-- Disable AOD -->
+        <option name="run-command" value="settings put secure doze_always_on 0"/>
         <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
         <option name="run-command" value="settings put system show_touches 1"/>
         <option name="run-command" value="settings put system pointer_location 1"/>
diff --git a/tests/FlickerTests/AppClose/AndroidTestTemplate.xml b/tests/FlickerTests/AppClose/AndroidTestTemplate.xml
index 3382c1e..5f92d7f 100644
--- a/tests/FlickerTests/AppClose/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/AppClose/AndroidTestTemplate.xml
@@ -45,6 +45,8 @@
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="test-user-token" value="%TEST_USER%"/>
         <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
+        <!-- Disable AOD -->
+        <option name="run-command" value="settings put secure doze_always_on 0"/>
         <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
         <option name="run-command" value="settings put system show_touches 1"/>
         <option name="run-command" value="settings put system pointer_location 1"/>
diff --git a/tests/FlickerTests/AppLaunch/AndroidTestTemplate.xml b/tests/FlickerTests/AppLaunch/AndroidTestTemplate.xml
index e941e79..1b90e99 100644
--- a/tests/FlickerTests/AppLaunch/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/AppLaunch/AndroidTestTemplate.xml
@@ -45,6 +45,8 @@
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="test-user-token" value="%TEST_USER%"/>
         <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
+        <!-- Disable AOD -->
+        <option name="run-command" value="settings put secure doze_always_on 0"/>
         <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
         <option name="run-command" value="settings put system show_touches 1"/>
         <option name="run-command" value="settings put system pointer_location 1"/>
diff --git a/tests/FlickerTests/FlickerService/AndroidTestTemplate.xml b/tests/FlickerTests/FlickerService/AndroidTestTemplate.xml
index 4e06dca..ffdbb02 100644
--- a/tests/FlickerTests/FlickerService/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/FlickerService/AndroidTestTemplate.xml
@@ -45,6 +45,8 @@
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="test-user-token" value="%TEST_USER%"/>
         <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
+        <!-- Disable AOD -->
+        <option name="run-command" value="settings put secure doze_always_on 0"/>
         <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
         <option name="run-command" value="settings put system show_touches 1"/>
         <option name="run-command" value="settings put system pointer_location 1"/>
diff --git a/tests/FlickerTests/IME/AndroidTestTemplate.xml b/tests/FlickerTests/IME/AndroidTestTemplate.xml
index 0cadd68..12670cd 100644
--- a/tests/FlickerTests/IME/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/IME/AndroidTestTemplate.xml
@@ -47,6 +47,8 @@
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="test-user-token" value="%TEST_USER%"/>
         <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
+        <!-- Disable AOD -->
+        <option name="run-command" value="settings put secure doze_always_on 0"/>
         <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
         <option name="run-command" value="settings put system show_touches 1"/>
         <option name="run-command" value="settings put system pointer_location 1"/>
diff --git a/tests/FlickerTests/Notification/AndroidTestTemplate.xml b/tests/FlickerTests/Notification/AndroidTestTemplate.xml
index f32e8bed..e2ac5a9 100644
--- a/tests/FlickerTests/Notification/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/Notification/AndroidTestTemplate.xml
@@ -45,6 +45,8 @@
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="test-user-token" value="%TEST_USER%"/>
         <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
+        <!-- Disable AOD -->
+        <option name="run-command" value="settings put secure doze_always_on 0"/>
         <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
         <option name="run-command" value="settings put system show_touches 1"/>
         <option name="run-command" value="settings put system pointer_location 1"/>
diff --git a/tests/FlickerTests/QuickSwitch/AndroidTestTemplate.xml b/tests/FlickerTests/QuickSwitch/AndroidTestTemplate.xml
index 68ae4f1..1a4feb6 100644
--- a/tests/FlickerTests/QuickSwitch/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/QuickSwitch/AndroidTestTemplate.xml
@@ -45,6 +45,8 @@
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="test-user-token" value="%TEST_USER%"/>
         <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
+        <!-- Disable AOD -->
+        <option name="run-command" value="settings put secure doze_always_on 0"/>
         <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
         <option name="run-command" value="settings put system show_touches 1"/>
         <option name="run-command" value="settings put system pointer_location 1"/>
diff --git a/tests/FlickerTests/Rotation/AndroidTestTemplate.xml b/tests/FlickerTests/Rotation/AndroidTestTemplate.xml
index ec186723..481a8bb 100644
--- a/tests/FlickerTests/Rotation/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/Rotation/AndroidTestTemplate.xml
@@ -45,6 +45,8 @@
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="test-user-token" value="%TEST_USER%"/>
         <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
+        <!-- Disable AOD -->
+        <option name="run-command" value="settings put secure doze_always_on 0"/>
         <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
         <option name="run-command" value="settings put system show_touches 1"/>
         <option name="run-command" value="settings put system pointer_location 1"/>
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
index 6432827..c1c5dc6 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
@@ -23,6 +23,7 @@
 import android.graphics.Region
 import android.os.SystemClock
 import android.platform.uiautomatorhelpers.DeviceHelpers
+import android.tools.PlatformConsts
 import android.tools.device.apphelpers.IStandardAppHelper
 import android.tools.helpers.SYSTEMUI_PACKAGE
 import android.tools.traces.parsers.WindowManagerStateHelper
@@ -38,6 +39,7 @@
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.helpers.MotionEventHelper.InputMethod.TOUCH
 import java.time.Duration
+import kotlin.math.abs
 
 /**
  * Wrapper class around App helper classes. This class adds functionality to the apps that the
@@ -163,7 +165,10 @@
             .StateSyncBuilder()
             .withAppTransitionIdle()
             .apply {
-                if (isPip) withPipShown() else withWindowSurfaceDisappeared(innerHelper)
+                if (isPip) withPipShown()
+                else
+                    withWindowSurfaceDisappeared(innerHelper)
+                        .withActivityState(innerHelper, PlatformConsts.STATE_STOPPED)
             }
             .waitForAndVerify()
     }
@@ -218,11 +223,16 @@
         val expectedRect = Rect(displayRect).apply {
             if (toLeft) right -= expectedWidth else left += expectedWidth
         }
-
-        wmHelper
-            .StateSyncBuilder()
+        wmHelper.StateSyncBuilder()
             .withAppTransitionIdle()
-            .withSurfaceVisibleRegion(this, Region(expectedRect))
+            .withSurfaceMatchingVisibleRegion(
+                this,
+                Region(expectedRect),
+                { surfaceRegion, expectedRegion ->
+                    areSnapWindowRegionsMatchingWithinThreshold(
+                        surfaceRegion, expectedRegion, toLeft
+                    )
+                })
             .waitForAndVerify()
     }
 
@@ -456,6 +466,33 @@
     private fun isInDesktopWindowingMode(wmHelper: WindowManagerStateHelper) =
         wmHelper.getWindow(innerHelper)?.windowingMode == WINDOWING_MODE_FREEFORM
 
+    private fun areSnapWindowRegionsMatchingWithinThreshold(
+        surfaceRegion: Region, expectedRegion: Region, toLeft: Boolean
+    ): Boolean {
+        val surfaceBounds = surfaceRegion.bounds
+        val expectedBounds = expectedRegion.bounds
+        // If snapped to left, right bounds will be cut off by the center divider.
+        // Else if snapped to right, the left bounds will be cut off.
+        val leftSideMatching: Boolean
+        val rightSideMatching: Boolean
+        if (toLeft) {
+            leftSideMatching = surfaceBounds.left == expectedBounds.left
+            rightSideMatching =
+                abs(surfaceBounds.right - expectedBounds.right) <=
+                        surfaceBounds.right * SNAP_WINDOW_MAX_THRESHOLD_DIFF
+        } else {
+            leftSideMatching =
+                abs(surfaceBounds.left - expectedBounds.left) <=
+                        surfaceBounds.left * SNAP_WINDOW_MAX_THRESHOLD_DIFF
+            rightSideMatching = surfaceBounds.right == expectedBounds.right
+        }
+
+        return surfaceBounds.top == expectedBounds.top &&
+                surfaceBounds.bottom == expectedBounds.bottom &&
+                leftSideMatching &&
+                rightSideMatching
+    }
+
     private companion object {
         val TIMEOUT: Duration = Duration.ofSeconds(3)
         const val SNAP_RESIZE_DRAG_INSET: Int = 5 // inset to avoid dragging to display edge
@@ -471,5 +508,12 @@
         const val HEADER_EMPTY_VIEW: String = "caption_handle"
         val caption: BySelector
             get() = By.res(SYSTEMUI_PACKAGE, CAPTION)
+        // In DesktopMode, window snap can be done with just a single window. In this case, the
+        // divider tiling between left and right window won't be shown, and hence its states are not
+        // obtainable in test.
+        // As the test should just focus on ensuring window goes to one side of the screen, an
+        // acceptable approach is to ensure snapped window still fills > 95% of either side of the
+        // screen.
+        const val SNAP_WINDOW_MAX_THRESHOLD_DIFF = 0.05
     }
 }
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GestureHelper.java b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GestureHelper.java
deleted file mode 100644
index eeee7b4..0000000
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GestureHelper.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.helpers;
-
-import android.annotation.NonNull;
-import android.app.Instrumentation;
-import android.app.UiAutomation;
-import android.os.SystemClock;
-import android.view.InputDevice;
-import android.view.InputEvent;
-import android.view.MotionEvent;
-import android.view.MotionEvent.PointerCoords;
-import android.view.MotionEvent.PointerProperties;
-
-import androidx.annotation.Nullable;
-
-/**
- * Injects gestures given an {@link Instrumentation} object.
- */
-public class GestureHelper {
-    // Inserted after each motion event injection.
-    private static final int MOTION_EVENT_INJECTION_DELAY_MILLIS = 5;
-
-    private final UiAutomation mUiAutomation;
-
-    /**
-     * Primary pointer should be cached here for separate release
-     */
-    @Nullable private PointerProperties mPrimaryPtrProp;
-    @Nullable private PointerCoords mPrimaryPtrCoord;
-    private long mPrimaryPtrDownTime;
-
-    /**
-     * A pair of floating point values.
-     */
-    public static class Tuple {
-        public float x;
-        public float y;
-
-        public Tuple(float x, float y) {
-            this.x = x;
-            this.y = y;
-        }
-    }
-
-    public GestureHelper(Instrumentation instrumentation) {
-        mUiAutomation = instrumentation.getUiAutomation();
-    }
-
-    /**
-     * Injects a series of {@link MotionEvent}s to simulate tapping.
-     *
-     * @param point coordinates of pointer to tap
-     * @param times the number of times to tap
-     */
-    public boolean tap(@NonNull Tuple point, int times) throws InterruptedException {
-        PointerProperties ptrProp = getPointerProp(0, MotionEvent.TOOL_TYPE_FINGER);
-        PointerCoords ptrCoord = getPointerCoord(point.x, point.y, 1, 1);
-
-        for (int i = 0; i <= times; i++) {
-            // If already tapped, inject delay in between movements
-            if (times > 0) {
-                SystemClock.sleep(50L);
-            }
-            if (!primaryPointerDown(ptrProp, ptrCoord, SystemClock.uptimeMillis())) {
-                return false;
-            }
-            // Delay before releasing tap
-            SystemClock.sleep(100L);
-            if (!primaryPointerUp(ptrProp, ptrCoord, SystemClock.uptimeMillis())) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Injects a series of {@link MotionEvent}s to simulate a drag gesture without pointer release.
-     *
-     * Simulates a drag gesture without releasing the primary pointer. The primary pointer info
-     * will be cached for potential release later on by {@code releasePrimaryPointer()}
-     *
-     * @param startPoint initial coordinates of the primary pointer
-     * @param endPoint final coordinates of the primary pointer
-     * @param steps number of steps to take to animate dragging
-     * @return true if gesture is injected successfully
-     */
-    public boolean dragWithoutRelease(@NonNull Tuple startPoint,
-            @NonNull Tuple endPoint, int steps) {
-        PointerProperties ptrProp = getPointerProp(0, MotionEvent.TOOL_TYPE_FINGER);
-        PointerCoords ptrCoord = getPointerCoord(startPoint.x, startPoint.y, 1, 1);
-
-        PointerProperties[] ptrProps = new PointerProperties[] { ptrProp };
-        PointerCoords[] ptrCoords = new PointerCoords[] { ptrCoord };
-
-        long downTime = SystemClock.uptimeMillis();
-
-        if (!primaryPointerDown(ptrProp, ptrCoord, downTime)) {
-            return false;
-        }
-
-        // cache the primary pointer info for later potential release
-        mPrimaryPtrProp = ptrProp;
-        mPrimaryPtrCoord = ptrCoord;
-        mPrimaryPtrDownTime = downTime;
-
-        return movePointers(ptrProps, ptrCoords, new Tuple[] { endPoint }, downTime, steps);
-    }
-
-    /**
-     * Release primary pointer if previous gesture has cached the primary pointer info.
-     *
-     * @return true if the release was injected successfully
-     */
-    public boolean releasePrimaryPointer() {
-        if (mPrimaryPtrProp != null && mPrimaryPtrCoord != null) {
-            return primaryPointerUp(mPrimaryPtrProp, mPrimaryPtrCoord, mPrimaryPtrDownTime);
-        }
-
-        return false;
-    }
-
-    /**
-     * Injects a series of {@link MotionEvent} objects to simulate a pinch gesture.
-     *
-     * @param startPoint1 initial coordinates of the first pointer
-     * @param startPoint2 initial coordinates of the second pointer
-     * @param endPoint1 final coordinates of the first pointer
-     * @param endPoint2 final coordinates of the second pointer
-     * @param steps number of steps to take to animate pinching
-     * @return true if gesture is injected successfully
-     */
-    public boolean pinch(@NonNull Tuple startPoint1, @NonNull Tuple startPoint2,
-            @NonNull Tuple endPoint1, @NonNull Tuple endPoint2, int steps) {
-        PointerProperties ptrProp1 = getPointerProp(0, MotionEvent.TOOL_TYPE_FINGER);
-        PointerProperties ptrProp2 = getPointerProp(1, MotionEvent.TOOL_TYPE_FINGER);
-
-        PointerCoords ptrCoord1 = getPointerCoord(startPoint1.x, startPoint1.y, 1, 1);
-        PointerCoords ptrCoord2 = getPointerCoord(startPoint2.x, startPoint2.y, 1, 1);
-
-        PointerProperties[] ptrProps = new PointerProperties[] {
-                ptrProp1, ptrProp2
-        };
-
-        PointerCoords[] ptrCoords = new PointerCoords[] {
-                ptrCoord1, ptrCoord2
-        };
-
-        long downTime = SystemClock.uptimeMillis();
-
-        if (!primaryPointerDown(ptrProp1, ptrCoord1, downTime)) {
-            return false;
-        }
-
-        if (!nonPrimaryPointerDown(ptrProps, ptrCoords, downTime, 1)) {
-            return false;
-        }
-
-        if (!movePointers(ptrProps, ptrCoords, new Tuple[] { endPoint1, endPoint2 },
-                downTime, steps)) {
-            return false;
-        }
-
-        if (!nonPrimaryPointerUp(ptrProps, ptrCoords, downTime, 1)) {
-            return false;
-        }
-
-        return primaryPointerUp(ptrProp1, ptrCoord1, downTime);
-    }
-
-    private boolean primaryPointerDown(@NonNull PointerProperties prop,
-            @NonNull PointerCoords coord, long downTime) {
-        MotionEvent event = getMotionEvent(downTime, downTime, MotionEvent.ACTION_DOWN, 1,
-                new PointerProperties[]{ prop }, new PointerCoords[]{ coord });
-
-        return injectEventSync(event);
-    }
-
-    private boolean nonPrimaryPointerDown(@NonNull PointerProperties[] props,
-            @NonNull PointerCoords[] coords, long downTime, int index) {
-        // at least 2 pointers are needed
-        if (props.length != coords.length || coords.length < 2) {
-            return false;
-        }
-
-        long eventTime = SystemClock.uptimeMillis();
-
-        MotionEvent event = getMotionEvent(downTime, eventTime, MotionEvent.ACTION_POINTER_DOWN
-                + (index << MotionEvent.ACTION_POINTER_INDEX_SHIFT), coords.length, props, coords);
-
-        return injectEventSync(event);
-    }
-
-    private boolean movePointers(@NonNull PointerProperties[] props,
-            @NonNull PointerCoords[] coords, @NonNull Tuple[] endPoints, long downTime, int steps) {
-        // the number of endpoints should be the same as the number of pointers
-        if (props.length != coords.length || coords.length != endPoints.length) {
-            return false;
-        }
-
-        // prevent division by 0 and negative number of steps
-        if (steps < 1) {
-            steps = 1;
-        }
-
-        // save the starting points before updating any pointers
-        Tuple[] startPoints = new Tuple[coords.length];
-
-        for (int i = 0; i < coords.length; i++) {
-            startPoints[i] = new Tuple(coords[i].x, coords[i].y);
-        }
-
-        MotionEvent event;
-        long eventTime;
-
-        for (int i = 0; i < steps; i++) {
-            // inject a delay between movements
-            SystemClock.sleep(MOTION_EVENT_INJECTION_DELAY_MILLIS);
-
-            // update the coordinates
-            for (int j = 0; j < coords.length; j++) {
-                coords[j].x += (endPoints[j].x - startPoints[j].x) / steps;
-                coords[j].y += (endPoints[j].y - startPoints[j].y) / steps;
-            }
-
-            eventTime = SystemClock.uptimeMillis();
-
-            event = getMotionEvent(downTime, eventTime, MotionEvent.ACTION_MOVE,
-                    coords.length, props, coords);
-
-            boolean didInject = injectEventSync(event);
-
-            if (!didInject) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    private boolean primaryPointerUp(@NonNull PointerProperties prop,
-            @NonNull PointerCoords coord, long downTime) {
-        long eventTime = SystemClock.uptimeMillis();
-
-        MotionEvent event = getMotionEvent(downTime, eventTime, MotionEvent.ACTION_UP, 1,
-                new PointerProperties[]{ prop }, new PointerCoords[]{ coord });
-
-        return injectEventSync(event);
-    }
-
-    private boolean nonPrimaryPointerUp(@NonNull PointerProperties[] props,
-            @NonNull PointerCoords[] coords, long downTime, int index) {
-        // at least 2 pointers are needed
-        if (props.length != coords.length || coords.length < 2) {
-            return false;
-        }
-
-        long eventTime = SystemClock.uptimeMillis();
-
-        MotionEvent event = getMotionEvent(downTime, eventTime, MotionEvent.ACTION_POINTER_UP
-                + (index << MotionEvent.ACTION_POINTER_INDEX_SHIFT), coords.length, props, coords);
-
-        return injectEventSync(event);
-    }
-
-    private PointerCoords getPointerCoord(float x, float y, float pressure, float size) {
-        PointerCoords ptrCoord = new PointerCoords();
-        ptrCoord.x = x;
-        ptrCoord.y = y;
-        ptrCoord.pressure = pressure;
-        ptrCoord.size = size;
-        return ptrCoord;
-    }
-
-    private PointerProperties getPointerProp(int id, int toolType) {
-        PointerProperties ptrProp = new PointerProperties();
-        ptrProp.id = id;
-        ptrProp.toolType = toolType;
-        return ptrProp;
-    }
-
-    private static MotionEvent getMotionEvent(long downTime, long eventTime, int action,
-            int pointerCount, PointerProperties[] ptrProps, PointerCoords[] ptrCoords) {
-        return MotionEvent.obtain(downTime, eventTime, action, pointerCount,
-                ptrProps, ptrCoords, 0, 0, 1.0f, 1.0f,
-                0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
-    }
-
-    private boolean injectEventSync(InputEvent event) {
-        return mUiAutomation.injectInputEvent(event, true);
-    }
-}
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
index fd13d14..d5334cb 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
@@ -21,6 +21,7 @@
 import android.graphics.Region
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.helpers.FIND_TIMEOUT
+import android.tools.helpers.GestureHelper
 import android.tools.helpers.SYSTEMUI_PACKAGE
 import android.tools.traces.component.ComponentNameMatcher
 import android.tools.traces.parsers.WindowManagerStateHelper
@@ -38,7 +39,8 @@
         ActivityOptions.NonResizeableFixedAspectRatioPortraitActivity.COMPONENT.toFlickerComponent()
 ) : StandardAppHelper(instr, launcherName, component) {
 
-    private val gestureHelper: GestureHelper = GestureHelper(instrumentation)
+    private val gestureHelper: GestureHelper =
+        GestureHelper(instrumentation)
 
     fun clickRestart(wmHelper: WindowManagerStateHelper) {
         val restartButton =
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
index 931e4f8..de17bf4 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -18,29 +18,26 @@
 
 import android.app.Instrumentation
 import android.content.Intent
-import android.graphics.Rect
 import android.graphics.Region
 import android.media.session.MediaController
 import android.media.session.MediaSessionManager
-import android.tools.datatypes.coversMoreThan
-import android.tools.device.apphelpers.StandardAppHelper
+import android.tools.device.apphelpers.BasePipAppHelper
 import android.tools.helpers.FIND_TIMEOUT
 import android.tools.helpers.SYSTEMUI_PACKAGE
 import android.tools.traces.ConditionsFactory
+import android.tools.traces.component.ComponentNameMatcher
 import android.tools.traces.component.IComponentMatcher
 import android.tools.traces.parsers.WindowManagerStateHelper
 import android.tools.traces.parsers.toFlickerComponent
-import android.util.Log
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.testapp.ActivityOptions
 
-open class PipAppHelper(instrumentation: Instrumentation) :
-    StandardAppHelper(
-        instrumentation,
-        ActivityOptions.Pip.LABEL,
-        ActivityOptions.Pip.COMPONENT.toFlickerComponent()
-    ) {
+open class PipAppHelper(
+    instrumentation: Instrumentation,
+    appName: String = ActivityOptions.Pip.LABEL,
+    componentNameMatcher: ComponentNameMatcher = ActivityOptions.Pip.COMPONENT.toFlickerComponent(),
+) : BasePipAppHelper(instrumentation, appName, componentNameMatcher) {
     private val mediaSessionManager: MediaSessionManager
         get() =
             context.getSystemService(MediaSessionManager::class.java)
@@ -52,189 +49,6 @@
                 it.packageName == packageName
             }
 
-    private val gestureHelper: GestureHelper = GestureHelper(instrumentation)
-
-    open fun clickObject(resId: String) {
-        val selector = By.res(packageName, resId)
-        val obj = uiDevice.findObject(selector) ?: error("Could not find `$resId` object")
-
-        obj.click()
-    }
-
-    /** Drags the PIP window to the provided final coordinates without releasing the pointer. */
-    fun dragPipWindowAwayFromEdgeWithoutRelease(wmHelper: WindowManagerStateHelper, steps: Int) {
-        val initWindowRect = Rect(getWindowRect(wmHelper))
-
-        // initial pointer at the center of the window
-        val initialCoord =
-            GestureHelper.Tuple(
-                initWindowRect.centerX().toFloat(),
-                initWindowRect.centerY().toFloat()
-            )
-
-        // the offset to the right (or left) of the window center to drag the window to
-        val offset = 50
-
-        // the actual final x coordinate with the offset included;
-        // if the pip window is closer to the right edge of the display the offset is negative
-        // otherwise the offset is positive
-        val endX =
-            initWindowRect.centerX() + offset * (if (isCloserToRightEdge(wmHelper)) -1 else 1)
-        val finalCoord = GestureHelper.Tuple(endX.toFloat(), initWindowRect.centerY().toFloat())
-
-        // drag to the final coordinate
-        gestureHelper.dragWithoutRelease(initialCoord, finalCoord, steps)
-    }
-
-    /**
-     * Releases the primary pointer.
-     *
-     * Injects the release of the primary pointer if the primary pointer info was cached after
-     * another gesture was injected without pointer release.
-     */
-    fun releasePipAfterDragging() {
-        gestureHelper.releasePrimaryPointer()
-    }
-
-    /**
-     * Drags the PIP window away from the screen edge while not crossing the display center.
-     *
-     * @throws IllegalStateException if default display bounds are not available
-     */
-    fun dragPipWindowAwayFromEdge(wmHelper: WindowManagerStateHelper, steps: Int) {
-        val initWindowRect = Rect(getWindowRect(wmHelper))
-
-        // initial pointer at the center of the window
-        val startX = initWindowRect.centerX()
-        val y = initWindowRect.centerY()
-
-        val displayRect =
-            wmHelper.currentState.wmState.getDefaultDisplay()?.displayRect
-                ?: throw IllegalStateException("Default display is null")
-
-        // the offset to the right (or left) of the display center to drag the window to
-        val offset = 20
-
-        // the actual final x coordinate with the offset included;
-        // if the pip window is closer to the right edge of the display the offset is positive
-        // otherwise the offset is negative
-        val endX = displayRect.centerX() + offset * (if (isCloserToRightEdge(wmHelper)) 1 else -1)
-
-        // drag the window to the left but not beyond the center of the display
-        uiDevice.drag(startX, y, endX, y, steps)
-    }
-
-    /**
-     * Returns true if PIP window is closer to the right edge of the display than left.
-     *
-     * @throws IllegalStateException if default display bounds are not available
-     */
-    fun isCloserToRightEdge(wmHelper: WindowManagerStateHelper): Boolean {
-        val windowRect = getWindowRect(wmHelper)
-
-        val displayRect =
-            wmHelper.currentState.wmState.getDefaultDisplay()?.displayRect
-                ?: throw IllegalStateException("Default display is null")
-
-        return windowRect.centerX() > displayRect.centerX()
-    }
-
-    /**
-     * Expands the PIP window by using the pinch out gesture.
-     *
-     * @param percent The percentage by which to increase the pip window size.
-     * @throws IllegalArgumentException if percentage isn't between 0.0f and 1.0f
-     */
-    fun pinchOpenPipWindow(wmHelper: WindowManagerStateHelper, percent: Float, steps: Int) {
-        // the percentage must be between 0.0f and 1.0f
-        if (percent <= 0.0f || percent > 1.0f) {
-            throw IllegalArgumentException("Percent must be between 0.0f and 1.0f")
-        }
-
-        val windowRect = getWindowRect(wmHelper)
-
-        // first pointer's initial x coordinate is halfway between the left edge and the center
-        val initLeftX = (windowRect.centerX() - windowRect.width() / 4).toFloat()
-        // second pointer's initial x coordinate is halfway between the right edge and the center
-        val initRightX = (windowRect.centerX() + windowRect.width() / 4).toFloat()
-
-        // horizontal distance the window should increase by
-        val distIncrease = windowRect.width() * percent
-
-        // final x-coordinates
-        val finalLeftX = initLeftX - (distIncrease / 2)
-        val finalRightX = initRightX + (distIncrease / 2)
-
-        // y-coordinate is the same throughout this animation
-        val yCoord = windowRect.centerY().toFloat()
-
-        var adjustedSteps = MIN_STEPS_TO_ANIMATE
-
-        // if distance per step is at least 1, then we can use the number of steps requested
-        if (distIncrease.toInt() / (steps * 2) >= 1) {
-            adjustedSteps = steps
-        }
-
-        // if the distance per step is less than 1, carry out the animation in two steps
-        gestureHelper.pinch(
-            GestureHelper.Tuple(initLeftX, yCoord),
-            GestureHelper.Tuple(initRightX, yCoord),
-            GestureHelper.Tuple(finalLeftX, yCoord),
-            GestureHelper.Tuple(finalRightX, yCoord),
-            adjustedSteps
-        )
-
-        waitForPipWindowToExpandFrom(wmHelper, Region(windowRect))
-    }
-
-    /**
-     * Minimizes the PIP window by using the pinch in gesture.
-     *
-     * @param percent The percentage by which to decrease the pip window size.
-     * @throws IllegalArgumentException if percentage isn't between 0.0f and 1.0f
-     */
-    fun pinchInPipWindow(wmHelper: WindowManagerStateHelper, percent: Float, steps: Int) {
-        // the percentage must be between 0.0f and 1.0f
-        if (percent <= 0.0f || percent > 1.0f) {
-            throw IllegalArgumentException("Percent must be between 0.0f and 1.0f")
-        }
-
-        val windowRect = getWindowRect(wmHelper)
-
-        // first pointer's initial x coordinate is halfway between the left edge and the center
-        val initLeftX = (windowRect.centerX() - windowRect.width() / 4).toFloat()
-        // second pointer's initial x coordinate is halfway between the right edge and the center
-        val initRightX = (windowRect.centerX() + windowRect.width() / 4).toFloat()
-
-        // decrease by the distance specified through the percentage
-        val distDecrease = windowRect.width() * percent
-
-        // get the final x-coordinates and make sure they are not passing the center of the window
-        val finalLeftX = Math.min(initLeftX + (distDecrease / 2), windowRect.centerX().toFloat())
-        val finalRightX = Math.max(initRightX - (distDecrease / 2), windowRect.centerX().toFloat())
-
-        // y-coordinate is the same throughout this animation
-        val yCoord = windowRect.centerY().toFloat()
-
-        var adjustedSteps = MIN_STEPS_TO_ANIMATE
-
-        // if distance per step is at least 1, then we can use the number of steps requested
-        if (distDecrease.toInt() / (steps * 2) >= 1) {
-            adjustedSteps = steps
-        }
-
-        // if the distance per step is less than 1, carry out the animation in two steps
-        gestureHelper.pinch(
-            GestureHelper.Tuple(initLeftX, yCoord),
-            GestureHelper.Tuple(initRightX, yCoord),
-            GestureHelper.Tuple(finalLeftX, yCoord),
-            GestureHelper.Tuple(finalRightX, yCoord),
-            adjustedSteps
-        )
-
-        waitForPipWindowToMinimizeFrom(wmHelper, Region(windowRect))
-    }
-
     /**
      * Launches the app through an intent instead of interacting with the launcher and waits until
      * the app window is in PIP mode
@@ -250,18 +64,13 @@
             wmHelper,
             launchedAppComponentMatcherOverride,
             action,
-            stringExtras,
-            waitConditionsBuilder =
-                wmHelper
-                    .StateSyncBuilder()
-                    .add(ConditionsFactory.isWMStateComplete())
-                    .withAppTransitionIdle()
-                    .add(ConditionsFactory.hasPipWindow())
+            stringExtras
         )
 
         wmHelper
             .StateSyncBuilder()
             .withWindowSurfaceAppeared(this)
+            .add(ConditionsFactory.isWMStateComplete())
             .withPipShown()
             .waitForAndVerify()
     }
@@ -336,126 +145,6 @@
         closePipWindow(WindowManagerStateHelper(instrumentation))
     }
 
-    /** Returns the pip window bounds. */
-    fun getWindowRect(wmHelper: WindowManagerStateHelper): Rect {
-        val windowRegion = wmHelper.getWindowRegion(this)
-        require(!windowRegion.isEmpty) { "Unable to find a PIP window in the current state" }
-        return windowRegion.bounds
-    }
-
-    /** Taps the pip window and dismisses it by clicking on the X button. */
-    open fun closePipWindow(wmHelper: WindowManagerStateHelper) {
-        val windowRect = getWindowRect(wmHelper)
-        uiDevice.click(windowRect.centerX(), windowRect.centerY())
-        // search and interact with the dismiss button
-        val dismissSelector = By.res(SYSTEMUI_PACKAGE, "dismiss")
-        uiDevice.wait(Until.hasObject(dismissSelector), FIND_TIMEOUT)
-        val dismissPipObject =
-            uiDevice.findObject(dismissSelector) ?: error("PIP window dismiss button not found")
-        val dismissButtonBounds = dismissPipObject.visibleBounds
-        uiDevice.click(dismissButtonBounds.centerX(), dismissButtonBounds.centerY())
-
-        // Wait for animation to complete.
-        wmHelper.StateSyncBuilder().withPipGone().withHomeActivityVisible().waitForAndVerify()
-    }
-
-    open fun tapPipToShowMenu(wmHelper: WindowManagerStateHelper) {
-        val windowRect = getWindowRect(wmHelper)
-        uiDevice.click(windowRect.centerX(), windowRect.centerY())
-        // search and interact with the dismiss button
-        val dismissSelector = By.res(SYSTEMUI_PACKAGE, "dismiss")
-        uiDevice.wait(Until.hasObject(dismissSelector), FIND_TIMEOUT)
-    }
-
-    /** Close the pip window by pressing the expand button */
-    fun expandPipWindowToApp(wmHelper: WindowManagerStateHelper) {
-        val windowRect = getWindowRect(wmHelper)
-        uiDevice.click(windowRect.centerX(), windowRect.centerY())
-        // search and interact with the expand button
-        val expandSelector = By.res(SYSTEMUI_PACKAGE, "expand_button")
-        uiDevice.wait(Until.hasObject(expandSelector), FIND_TIMEOUT)
-        val expandPipObject =
-            uiDevice.findObject(expandSelector) ?: error("PIP window expand button not found")
-        val expandButtonBounds = expandPipObject.visibleBounds
-        uiDevice.click(expandButtonBounds.centerX(), expandButtonBounds.centerY())
-        wmHelper.StateSyncBuilder().withPipGone().withFullScreenApp(this).waitForAndVerify()
-    }
-
-    /** Double click on the PIP window to expand it */
-    fun doubleClickPipWindow(wmHelper: WindowManagerStateHelper) {
-        val windowRect = getWindowRect(wmHelper)
-        Log.d(TAG, "First click")
-        uiDevice.click(windowRect.centerX(), windowRect.centerY())
-        Log.d(TAG, "Second click")
-        uiDevice.click(windowRect.centerX(), windowRect.centerY())
-        Log.d(TAG, "Wait for app transition to end")
-        wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
-        waitForPipWindowToExpandFrom(wmHelper, Region(windowRect))
-    }
-
-    private fun waitForPipWindowToExpandFrom(
-        wmHelper: WindowManagerStateHelper,
-        windowRect: Region
-    ) {
-        wmHelper
-            .StateSyncBuilder()
-            .add("pipWindowExpanded") {
-                val pipAppWindow =
-                    it.wmState.visibleWindows.firstOrNull { window ->
-                        this.windowMatchesAnyOf(window)
-                    }
-                        ?: return@add false
-                val pipRegion = pipAppWindow.frameRegion
-                return@add pipRegion.coversMoreThan(windowRect)
-            }
-            .waitForAndVerify()
-    }
-
-    private fun waitForPipWindowToMinimizeFrom(
-        wmHelper: WindowManagerStateHelper,
-        windowRect: Region
-    ) {
-        wmHelper
-            .StateSyncBuilder()
-            .add("pipWindowMinimized") {
-                val pipAppWindow =
-                    it.wmState.visibleWindows.firstOrNull { window ->
-                        this.windowMatchesAnyOf(window)
-                    }
-                Log.d(TAG, "window " + pipAppWindow)
-                if (pipAppWindow == null) return@add false
-                val pipRegion = pipAppWindow.frameRegion
-                Log.d(
-                    TAG,
-                    "region " + pipRegion + " covers " + windowRect.coversMoreThan(pipRegion)
-                )
-                return@add windowRect.coversMoreThan(pipRegion)
-            }
-            .waitForAndVerify()
-    }
-
-    /**
-     * Waits until the PIP window snaps horizontally to the provided bounds.
-     *
-     * @param finalBounds the bounds to wait for PIP window to snap to
-     */
-    fun waitForPipToSnapTo(wmHelper: WindowManagerStateHelper, finalBounds: android.graphics.Rect) {
-        wmHelper
-            .StateSyncBuilder()
-            .add("pipWindowSnapped") {
-                val pipAppWindow =
-                    it.wmState.visibleWindows.firstOrNull { window ->
-                        this.windowMatchesAnyOf(window)
-                    }
-                        ?: return@add false
-                val pipRegionBounds = pipAppWindow.frameRegion.bounds
-                return@add pipRegionBounds.left == finalBounds.left &&
-                    pipRegionBounds.right == finalBounds.right
-            }
-            .add(ConditionsFactory.isWMStateComplete())
-            .waitForAndVerify()
-    }
-
     companion object {
         private const val TAG = "PipAppHelper"
         private const val ENTER_PIP_BUTTON_ID = "enter_pip"
@@ -464,8 +153,5 @@
         private const val ENTER_PIP_ON_USER_LEAVE_HINT = "enter_pip_on_leave_manual"
         private const val ENTER_PIP_AUTOENTER = "enter_pip_on_leave_autoenter"
         private const val SOURCE_RECT_HINT = "set_source_rect_hint"
-        // minimum number of steps to take, when animating gestures, needs to be 2
-        // so that there is at least a single intermediate layer that flicker tests can check
-        private const val MIN_STEPS_TO_ANIMATE = 2
     }
-}
+}
\ No newline at end of file
diff --git a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
index fe974e3..af87bf7 100644
--- a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
@@ -1014,7 +1014,7 @@
             triggerFailureCount = 1;
         }
         for (int i = 0; i < triggerFailureCount; i++) {
-            watchdog.onPackageFailure(packages, failureReason);
+            watchdog.notifyPackageFailure(packages, failureReason);
         }
         mTestLooper.dispatchAll();
         if (Flags.recoverabilityDetection()) {
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index c25bed2..5a8a6be 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -392,7 +392,7 @@
 
         // Then fail APP_A below the threshold
         for (int i = 0; i < watchdog.getTriggerFailureCount() - 1; i++) {
-            watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+            watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
                     PackageWatchdog.FAILURE_REASON_UNKNOWN);
         }
 
@@ -1025,14 +1025,14 @@
         watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION);
         // Fail APP_A below the threshold which should not trigger package failures
         for (int i = 0; i < PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT - 1; i++) {
-            watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+            watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
                     PackageWatchdog.FAILURE_REASON_UNKNOWN);
         }
         mTestLooper.dispatchAll();
         assertThat(observer.mHealthCheckFailedPackages).isEmpty();
 
         // One more to trigger the package failure
-        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+        watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
                 PackageWatchdog.FAILURE_REASON_UNKNOWN);
         mTestLooper.dispatchAll();
         assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_A);
@@ -1051,10 +1051,10 @@
         TestObserver observer = new TestObserver(OBSERVER_NAME_1);
 
         watchdog.startObservingHealth(observer, Arrays.asList(APP_A, APP_B), Long.MAX_VALUE);
-        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+        watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
                 PackageWatchdog.FAILURE_REASON_UNKNOWN);
         moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS + 1);
-        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+        watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
                 PackageWatchdog.FAILURE_REASON_UNKNOWN);
         mTestLooper.dispatchAll();
 
@@ -1062,10 +1062,10 @@
         // DEFAULT_TRIGGER_FAILURE_DURATION_MS.
         assertThat(observer.mHealthCheckFailedPackages).isEmpty();
 
-        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)),
+        watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)),
                 PackageWatchdog.FAILURE_REASON_UNKNOWN);
         moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS - 1);
-        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)),
+        watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)),
                 PackageWatchdog.FAILURE_REASON_UNKNOWN);
         mTestLooper.dispatchAll();
 
@@ -1129,17 +1129,17 @@
 
         watchdog.startObservingHealth(observer, Arrays.asList(APP_A), Long.MAX_VALUE);
         // Raise 2 failures at t=0 and t=900 respectively
-        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+        watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
                 PackageWatchdog.FAILURE_REASON_UNKNOWN);
         moveTimeForwardAndDispatch(900);
-        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+        watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
                 PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // Raise 2 failures at t=1100
         moveTimeForwardAndDispatch(200);
-        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+        watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
                 PackageWatchdog.FAILURE_REASON_UNKNOWN);
-        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+        watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
                 PackageWatchdog.FAILURE_REASON_UNKNOWN);
         mTestLooper.dispatchAll();
 
@@ -1433,13 +1433,13 @@
         TestObserver observer = new TestObserver(OBSERVER_NAME_1);
         watchdog.startObservingHealth(observer, List.of(APP_A), SHORT_DURATION);
         for (int i = 0; i < PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT - 1; i++) {
-            watchdog.onPackageFailure(List.of(new VersionedPackage(APP_A, VERSION_CODE)),
+            watchdog.notifyPackageFailure(List.of(new VersionedPackage(APP_A, VERSION_CODE)),
                     PackageWatchdog.FAILURE_REASON_UNKNOWN);
         }
         mTestLooper.dispatchAll();
         assertThat(observer.mMitigatedPackages).isEmpty();
         watchdog.startObservingHealth(observer, List.of(APP_A), LONG_DURATION);
-        watchdog.onPackageFailure(List.of(new VersionedPackage(APP_A, VERSION_CODE)),
+        watchdog.notifyPackageFailure(List.of(new VersionedPackage(APP_A, VERSION_CODE)),
                 PackageWatchdog.FAILURE_REASON_UNKNOWN);
         mTestLooper.dispatchAll();
         assertThat(observer.mMitigatedPackages).isEqualTo(List.of(APP_A));
@@ -1737,7 +1737,7 @@
             triggerFailureCount = 1;
         }
         for (int i = 0; i < triggerFailureCount; i++) {
-            watchdog.onPackageFailure(packages, failureReason);
+            watchdog.notifyPackageFailure(packages, failureReason);
         }
         mTestLooper.dispatchAll();
         if (Flags.recoverabilityDetection()) {
diff --git a/tests/Tracing/src/com/android/internal/protolog/LegacyProtoLogImplTest.java b/tests/Tracing/src/com/android/internal/protolog/LegacyProtoLogImplTest.java
index 8913e8c..0530846 100644
--- a/tests/Tracing/src/com/android/internal/protolog/LegacyProtoLogImplTest.java
+++ b/tests/Tracing/src/com/android/internal/protolog/LegacyProtoLogImplTest.java
@@ -89,7 +89,7 @@
         //noinspection ResultOfMethodCallIgnored
         mFile.delete();
         mProtoLog = new LegacyProtoLogImpl(mFile, mViewerConfigFilename,
-                1024 * 1024, mReader, 1024, () -> {});
+                1024 * 1024, mReader, 1024, (instance) -> {});
     }
 
     @After
diff --git a/tests/Tracing/src/com/android/internal/protolog/ProcessedPerfettoProtoLogImplTest.java b/tests/Tracing/src/com/android/internal/protolog/ProcessedPerfettoProtoLogImplTest.java
index 44641f7..ed256e7 100644
--- a/tests/Tracing/src/com/android/internal/protolog/ProcessedPerfettoProtoLogImplTest.java
+++ b/tests/Tracing/src/com/android/internal/protolog/ProcessedPerfettoProtoLogImplTest.java
@@ -41,6 +41,7 @@
 import android.tools.traces.monitors.PerfettoTraceMonitor;
 import android.tools.traces.protolog.ProtoLogTrace;
 import android.tracing.perfetto.DataSource;
+import android.tracing.perfetto.DataSourceParams;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
@@ -95,14 +96,14 @@
     );
 
     private static ProtoLogConfigurationService sProtoLogConfigurationService;
+    private static ProtoLogDataSource sTestDataSource;
     private static PerfettoProtoLogImpl sProtoLog;
     private static Protolog.ProtoLogViewerConfig.Builder sViewerConfigBuilder;
-    private static Runnable sCacheUpdater;
+    private static ProtoLogCacheUpdater sCacheUpdater;
 
     private static ProtoLogViewerConfigReader sReader;
 
-    public ProcessedPerfettoProtoLogImplTest() throws IOException {
-    }
+    public ProcessedPerfettoProtoLogImplTest() throws IOException { }
 
     @BeforeClass
     public static void setUp() throws Exception {
@@ -155,12 +156,18 @@
                 .thenAnswer(it -> new AutoClosableProtoInputStream(
                         sViewerConfigBuilder.build().toByteArray()));
 
-        sCacheUpdater = () -> {};
+        sCacheUpdater = (instance) -> {};
         sReader = Mockito.spy(new ProtoLogViewerConfigReader(viewerConfigInputStreamProvider));
+        sTestDataSource = new ProtoLogDataSource(TEST_PROTOLOG_DATASOURCE_NAME);
+        DataSourceParams params =
+                new DataSourceParams.Builder()
+                        .setBufferExhaustedPolicy(
+                                DataSourceParams
+                                        .PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP)
+                        .build();
+        sTestDataSource.register(params);
+        busyWaitForDataSourceRegistration(TEST_PROTOLOG_DATASOURCE_NAME);
 
-        final ProtoLogDataSourceBuilder dataSourceBuilder =
-                (onStart, onFlush, onStop) -> new ProtoLogDataSource(
-                        onStart, onFlush, onStop, TEST_PROTOLOG_DATASOURCE_NAME);
         final ViewerConfigFileTracer tracer = (dataSource, viewerConfigFilePath) -> {
             Utils.dumpViewerConfig(dataSource, () -> {
                 if (!viewerConfigFilePath.equals(MOCK_VIEWER_CONFIG_FILE)) {
@@ -171,14 +178,13 @@
             });
         };
         sProtoLogConfigurationService =
-                new ProtoLogConfigurationServiceImpl(dataSourceBuilder, tracer);
+                new ProtoLogConfigurationServiceImpl(sTestDataSource, tracer);
 
-        sProtoLog = new ProcessedPerfettoProtoLogImpl(
+        sProtoLog = new ProcessedPerfettoProtoLogImpl(sTestDataSource,
                 MOCK_VIEWER_CONFIG_FILE, viewerConfigInputStreamProvider, sReader,
-                () -> sCacheUpdater.run(), TestProtoLogGroup.values(), dataSourceBuilder,
+                (instance) -> sCacheUpdater.update(instance), TestProtoLogGroup.values(),
                 sProtoLogConfigurationService);
-
-        busyWaitForDataSourceRegistration(TEST_PROTOLOG_DATASOURCE_NAME);
+        sProtoLog.enable();
     }
 
     @Before
@@ -606,7 +612,7 @@
     @Test
     public void cacheIsUpdatedWhenTracesStartAndStop() {
         final AtomicInteger cacheUpdateCallCount = new AtomicInteger(0);
-        sCacheUpdater = cacheUpdateCallCount::incrementAndGet;
+        sCacheUpdater = (instance) -> cacheUpdateCallCount.incrementAndGet();
 
         PerfettoTraceMonitor traceMonitor1 = PerfettoTraceMonitor.newBuilder()
                 .enableProtoLog(true,
diff --git a/tests/Tracing/src/com/android/internal/protolog/ProtologDataSourceTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtologDataSourceTest.java
index ce519b7a..4924933 100644
--- a/tests/Tracing/src/com/android/internal/protolog/ProtologDataSourceTest.java
+++ b/tests/Tracing/src/com/android/internal/protolog/ProtologDataSourceTest.java
@@ -67,9 +67,6 @@
 
     @Test
     public void allEnabledTraceMode() {
-        final ProtoLogDataSource ds =
-                new ProtoLogDataSource((idx, c) -> {}, () -> {}, (idx, c) -> {});
-
         final ProtoLogDataSource.TlsState tlsState = createTlsState(
                 DataSourceConfigOuterClass.DataSourceConfig.newBuilder().setProtologConfig(
                         ProtologConfig.ProtoLogConfig.newBuilder()
@@ -154,8 +151,7 @@
 
     private ProtoLogDataSource.TlsState createTlsState(
             DataSourceConfigOuterClass.DataSourceConfig config) {
-        final ProtoLogDataSource ds =
-                Mockito.spy(new ProtoLogDataSource((idx, c) -> {}, () -> {}, (idx, c) -> {}));
+        final ProtoLogDataSource ds = Mockito.spy(new ProtoLogDataSource());
 
         ProtoInputStream configStream = new ProtoInputStream(config.toByteArray());
         final ProtoLogDataSource.Instance dsInstance = Mockito.spy(
diff --git a/tests/broadcasts/unit/Android.bp b/tests/broadcasts/unit/Android.bp
new file mode 100644
index 0000000..9e15ac4
--- /dev/null
+++ b/tests/broadcasts/unit/Android.bp
@@ -0,0 +1,44 @@
+// 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+    default_team: "trendy_team_framework_backstage_power",
+}
+
+android_test {
+    name: "BroadcastUnitTests",
+    srcs: ["src/**/*.java"],
+    defaults: [
+        "modules-utils-extended-mockito-rule-defaults",
+    ],
+    static_libs: [
+        "androidx.test.runner",
+        "androidx.test.rules",
+        "androidx.test.ext.junit",
+        "mockito-target-extended-minus-junit4",
+        "truth",
+        "flag-junit",
+        "android.app.flags-aconfig-java",
+        "junit-params",
+    ],
+    certificate: "platform",
+    platform_apis: true,
+    test_suites: ["device-tests"],
+}
diff --git a/tests/broadcasts/unit/AndroidManifest.xml b/tests/broadcasts/unit/AndroidManifest.xml
new file mode 100644
index 0000000..61eb230
--- /dev/null
+++ b/tests/broadcasts/unit/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.broadcasts.unit" >
+
+    <application android:debuggable="true">
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.broadcasts.unit"
+        android:label="Broadcasts Unit Tests"/>
+</manifest>
\ No newline at end of file
diff --git a/tests/broadcasts/unit/AndroidTest.xml b/tests/broadcasts/unit/AndroidTest.xml
new file mode 100644
index 0000000..b91e4783
--- /dev/null
+++ b/tests/broadcasts/unit/AndroidTest.xml
@@ -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.
+-->
+<configuration description="Runs Broadcasts tests">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="BroadcastUnitTests" />
+
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="BroadcastUnitTests.apk" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.broadcasts.unit" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/broadcasts/unit/OWNERS b/tests/broadcasts/unit/OWNERS
new file mode 100644
index 0000000..f1e450b
--- /dev/null
+++ b/tests/broadcasts/unit/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 316181
+include platform/frameworks/base:/BROADCASTS_OWNERS
\ No newline at end of file
diff --git a/tests/broadcasts/unit/TEST_MAPPING b/tests/broadcasts/unit/TEST_MAPPING
new file mode 100644
index 0000000..b920e25
--- /dev/null
+++ b/tests/broadcasts/unit/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+    "postsubmit": [
+        {
+            "name": "BroadcastUnitTests"
+        }
+    ]
+}
diff --git a/tests/broadcasts/unit/src/android/app/BroadcastStickyCacheTest.java b/tests/broadcasts/unit/src/android/app/BroadcastStickyCacheTest.java
new file mode 100644
index 0000000..ad032fb
--- /dev/null
+++ b/tests/broadcasts/unit/src/android/app/BroadcastStickyCacheTest.java
@@ -0,0 +1,231 @@
+/*
+ * 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.app;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
+import android.os.IpcDataCache;
+import android.os.RemoteException;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.annotations.Keep;
+import com.android.modules.utils.testing.ExtendedMockitoRule;
+
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@RunWith(JUnitParamsRunner.class)
+public class BroadcastStickyCacheTest {
+
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+    @Rule
+    public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this)
+            .mockStatic(IpcDataCache.class)
+            .mockStatic(ActivityManager.class)
+            .build();
+
+    @Mock
+    private IActivityManager mActivityManagerMock;
+
+    @Mock
+    private IApplicationThread mIApplicationThreadMock;
+
+    @Keep
+    private static Object stickyBroadcastList() {
+        return BroadcastStickyCache.STICKY_BROADCAST_ACTIONS;
+    }
+
+    @Before
+    public void setUp() {
+        BroadcastStickyCache.clearCacheForTest();
+
+        doNothing().when(() -> IpcDataCache.invalidateCache(anyString(), anyString()));
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_USE_STICKY_BCAST_CACHE)
+    public void useCache_flagDisabled_returnsFalse() {
+        assertFalse(BroadcastStickyCache.useCache(new IntentFilter(Intent.ACTION_BATTERY_CHANGED)));
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_USE_STICKY_BCAST_CACHE)
+    public void useCache_nullFilter_returnsFalse() {
+        assertFalse(BroadcastStickyCache.useCache(null));
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_USE_STICKY_BCAST_CACHE)
+    public void useCache_filterWithoutAction_returnsFalse() {
+        assertFalse(BroadcastStickyCache.useCache(new IntentFilter()));
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_USE_STICKY_BCAST_CACHE)
+    public void useCache_filterWithoutStickyBroadcastAction_returnsFalse() {
+        assertFalse(BroadcastStickyCache.useCache(new IntentFilter(Intent.ACTION_BOOT_COMPLETED)));
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_USE_STICKY_BCAST_CACHE)
+    public void invalidateCache_flagDisabled_cacheNotInvalidated() {
+        final String apiName = BroadcastStickyCache.sActionApiNameMap.get(
+                AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
+
+        BroadcastStickyCache.invalidateCache(
+                AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
+
+        ExtendedMockito.verify(
+                () -> IpcDataCache.invalidateCache(eq(IpcDataCache.MODULE_SYSTEM), eq(apiName)),
+                times(0));
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_USE_STICKY_BCAST_CACHE)
+    public void invalidateCache_broadcastNotSticky_cacheNotInvalidated() {
+        BroadcastStickyCache.invalidateCache(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+
+        ExtendedMockito.verify(
+                () -> IpcDataCache.invalidateCache(eq(IpcDataCache.MODULE_SYSTEM), anyString()),
+                times(0));
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_USE_STICKY_BCAST_CACHE)
+    public void invalidateCache_withStickyBroadcast_cacheInvalidated() {
+        final String apiName = BroadcastStickyCache.sActionApiNameMap.get(
+                Intent.ACTION_BATTERY_CHANGED);
+
+        BroadcastStickyCache.invalidateCache(Intent.ACTION_BATTERY_CHANGED);
+
+        ExtendedMockito.verify(
+                () -> IpcDataCache.invalidateCache(eq(IpcDataCache.MODULE_SYSTEM), eq(apiName)),
+                times(1));
+    }
+
+    @Test
+    public void invalidateAllCaches_cacheInvalidated() {
+        BroadcastStickyCache.invalidateAllCaches();
+
+        for (int i = BroadcastStickyCache.sActionApiNameMap.size() - 1; i > -1; i--) {
+            final String apiName = BroadcastStickyCache.sActionApiNameMap.valueAt(i);
+            ExtendedMockito.verify(() -> IpcDataCache.invalidateCache(anyString(),
+                    eq(apiName)), times(1));
+        }
+    }
+
+    @Test
+    @Parameters(method = "stickyBroadcastList")
+    public void getIntent_createNewCache_verifyRegisterReceiverIsCalled(String action)
+            throws RemoteException {
+        setActivityManagerMock(action);
+        final IntentFilter filter = new IntentFilter(action);
+        final Intent intent = queryIntent(filter);
+
+        assertNotNull(intent);
+        assertEquals(intent.getAction(), action);
+        verify(mActivityManagerMock, times(1)).registerReceiverWithFeature(
+                eq(mIApplicationThreadMock), anyString(), anyString(), anyString(), any(),
+                eq(filter), anyString(), anyInt(), anyInt());
+    }
+
+    @Test
+    public void getIntent_querySameValueTwice_verifyRegisterReceiverIsCalledOnce()
+            throws RemoteException {
+        setActivityManagerMock(Intent.ACTION_DEVICE_STORAGE_LOW);
+        final Intent intent = queryIntent(new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW));
+        final Intent cachedIntent = queryIntent(new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW));
+
+        assertNotNull(intent);
+        assertEquals(intent.getAction(), Intent.ACTION_DEVICE_STORAGE_LOW);
+        assertNotNull(cachedIntent);
+        assertEquals(cachedIntent.getAction(), Intent.ACTION_DEVICE_STORAGE_LOW);
+
+        verify(mActivityManagerMock, times(1)).registerReceiverWithFeature(
+                eq(mIApplicationThreadMock), anyString(), anyString(), anyString(), any(),
+                any(), anyString(), anyInt(), anyInt());
+    }
+
+    @Test
+    public void getIntent_querySameActionWithDifferentFilter_verifyRegisterReceiverCalledTwice()
+            throws RemoteException {
+        setActivityManagerMock(Intent.ACTION_DEVICE_STORAGE_LOW);
+        final IntentFilter filter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW);
+        final Intent intent = queryIntent(filter);
+
+        final IntentFilter newFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW);
+        newFilter.addDataScheme("file");
+        final Intent newIntent = queryIntent(newFilter);
+
+        assertNotNull(intent);
+        assertEquals(intent.getAction(), Intent.ACTION_DEVICE_STORAGE_LOW);
+        assertNotNull(newIntent);
+        assertEquals(newIntent.getAction(), Intent.ACTION_DEVICE_STORAGE_LOW);
+
+        verify(mActivityManagerMock, times(1)).registerReceiverWithFeature(
+                eq(mIApplicationThreadMock), anyString(), anyString(), anyString(), any(),
+                eq(filter), anyString(), anyInt(), anyInt());
+
+        verify(mActivityManagerMock, times(1)).registerReceiverWithFeature(
+                eq(mIApplicationThreadMock), anyString(), anyString(), anyString(), any(),
+                eq(newFilter), anyString(), anyInt(), anyInt());
+    }
+
+    private Intent queryIntent(IntentFilter filter) {
+        return BroadcastStickyCache.getIntent(
+                mIApplicationThreadMock,
+                "android",
+                "android",
+                filter,
+                "system",
+                0,
+                0
+        );
+    }
+
+    private void setActivityManagerMock(String action) throws RemoteException {
+        when(ActivityManager.getService()).thenReturn(mActivityManagerMock);
+        when(mActivityManagerMock.registerReceiverWithFeature(any(), anyString(),
+                anyString(), anyString(), any(), any(), anyString(), anyInt(),
+                anyInt())).thenReturn(new Intent(action));
+    }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java b/tests/vcn/java/android/net/vcn/util/MtuUtilsTest.java
similarity index 97%
rename from tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java
rename to tests/vcn/java/android/net/vcn/util/MtuUtilsTest.java
index e9e7078..47638b0 100644
--- a/tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java
+++ b/tests/vcn/java/android/net/vcn/util/MtuUtilsTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.vcn.util;
+package android.net.vcn.util;
 
 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC;
 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
@@ -22,10 +22,10 @@
 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8;
 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128;
 import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_256;
+import static android.net.vcn.util.MtuUtils.getMtu;
 
 import static com.android.net.module.util.NetworkStackConstants.ETHER_MTU;
 import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
-import static com.android.server.vcn.util.MtuUtils.getMtu;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
diff --git a/tests/vcn/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java b/tests/vcn/java/android/net/vcn/util/PersistableBundleUtilsTest.java
similarity index 99%
rename from tests/vcn/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java
rename to tests/vcn/java/android/net/vcn/util/PersistableBundleUtilsTest.java
index 9c6d852..c84e600 100644
--- a/tests/vcn/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java
+++ b/tests/vcn/java/android/net/vcn/util/PersistableBundleUtilsTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.vcn.util;
+package android.net.vcn.util;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 4ab8e6a..26a2a06 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -77,6 +77,8 @@
 import android.net.vcn.VcnGatewayConnectionConfigTest;
 import android.net.vcn.VcnManager;
 import android.net.vcn.VcnUnderlyingNetworkPolicy;
+import android.net.vcn.util.PersistableBundleUtils;
+import android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 import android.os.IBinder;
 import android.os.ParcelUuid;
 import android.os.PersistableBundle;
@@ -99,8 +101,6 @@
 import com.android.server.vcn.Vcn;
 import com.android.server.vcn.VcnContext;
 import com.android.server.vcn.VcnNetworkProvider;
-import com.android.server.vcn.util.PersistableBundleUtils;
-import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
index f1f74bc..b999475 100644
--- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -19,6 +19,7 @@
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.vcn.VcnManager.VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY;
+import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
@@ -26,7 +27,6 @@
 
 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
-import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 20b7f1f..76be232 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -69,6 +69,7 @@
 import android.net.vcn.VcnGatewayConnectionConfigTest;
 import android.net.vcn.VcnManager.VcnErrorCode;
 import android.net.vcn.VcnTransportInfo;
+import android.net.vcn.util.MtuUtils;
 import android.os.PersistableBundle;
 
 import androidx.test.filters.SmallTest;
@@ -79,7 +80,6 @@
 import com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
 import com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent;
 import com.android.server.vcn.routeselection.UnderlyingNetworkRecord;
-import com.android.server.vcn.util.MtuUtils;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
index 613b926..b9fe76a 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
@@ -25,13 +25,13 @@
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.vcn.VcnGatewayConnectionConfig.VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY;
+import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR;
 import static com.android.server.vcn.VcnGatewayConnection.SAFEMODE_TIMEOUT_SECONDS;
 import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration;
 import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
 import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent;
-import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
index 441a4ae..5db02e3 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
@@ -19,11 +19,11 @@
 import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY;
 import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY;
 import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY;
+import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DISABLE_DETECTOR;
 import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.MIN_VALID_EXPECTED_RX_PACKET_NUM;
 import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.getMaxSeqNumIncreasePerSecond;
-import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
index d85c515..4f34f9f 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
@@ -23,13 +23,13 @@
 import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS;
 import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS;
 import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS;
+import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_FALLBACK;
 import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_INVALID;
 import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesCellPriorityRule;
 import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesPriorityRule;
 import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesWifiPriorityRule;
-import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java
index 1d68721..a315b069 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java
@@ -17,9 +17,9 @@
 package com.android.server.vcn.routeselection;
 
 import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_PENALTY_TIMEOUT_MINUTES_LIST_KEY;
+import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_INVALID;
-import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h
index 40ff5b6..03da460a 100644
--- a/tools/aapt2/util/Util.h
+++ b/tools/aapt2/util/Util.h
@@ -111,8 +111,8 @@
 // Retrieves the build fingerprint of aapt2.
 std::string GetToolFingerprint();
 
-template <typename T>
-typename std::enable_if<std::is_arithmetic<T>::value, int>::type compare(const T& a, const T& b) {
+template <std::integral T>
+int compare(T a, T b) {
   if (a < b) {
     return -1;
   } else if (a > b) {
@@ -123,10 +123,7 @@
 
 // Makes a std::unique_ptr<> with the template parameter inferred by the compiler.
 // This will be present in C++14 and can be removed then.
-template <typename T, class... Args>
-std::unique_ptr<T> make_unique(Args&&... args) {
-  return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
-}
+using std::make_unique;
 
 // Writes a set of items to the std::ostream, joining the times with the provided separator.
 template <typename Container>
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
index 108942e..9222ff4 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
@@ -16,6 +16,7 @@
 
 package com.android.protolog.tool
 
+import com.android.internal.protolog.common.IProtoLog
 import com.android.internal.protolog.common.LogLevel
 import com.android.internal.protolog.common.ProtoLogToolInjected
 import com.android.protolog.tool.CommandOptions.Companion.USAGE
@@ -319,6 +320,7 @@
                             MethodCallExpr()
                                 .setName("isEnabled")
                                 .setArguments(NodeList(
+                                    NameExpr("protoLogInstance"),
                                     FieldAccessExpr()
                                         .setScope(NameExpr(protoLogGroupsClassName))
                                         .setName(group.value.name),
@@ -332,6 +334,7 @@
         }
 
         cacheClass.addMethod("update").setPrivate(true).setStatic(true)
+            .addParameter(IProtoLog::class.java, "protoLogInstance")
             .setBody(updateBlockStmt)
 
         classDeclaration.addMember(cacheClass)
diff --git a/tools/systemfeatures/Android.bp b/tools/systemfeatures/Android.bp
index e6d0a3d..2ebede3 100644
--- a/tools/systemfeatures/Android.bp
+++ b/tools/systemfeatures/Android.bp
@@ -13,6 +13,7 @@
     srcs: [
         "src/**/*.java",
         "src/**/*.kt",
+        ":framework-metalava-annotations",
     ],
     static_libs: [
         "guava",
@@ -26,6 +27,12 @@
     static_libs: ["systemfeatures-gen-lib"],
 }
 
+java_plugin {
+    name: "systemfeatures-metadata-processor",
+    processor_class: "com.android.systemfeatures.SystemFeaturesMetadataProcessor",
+    static_libs: ["systemfeatures-gen-lib"],
+}
+
 genrule {
     name: "systemfeatures-gen-tests-srcs",
     cmd: "$(location systemfeatures-gen-tool) com.android.systemfeatures.RwNoFeatures --readonly=false > $(location RwNoFeatures.java) && " +
@@ -61,6 +68,7 @@
         "systemfeatures-gen-lib",
         "truth",
     ],
+    plugins: ["systemfeatures-metadata-processor"],
 }
 
 // Rename the goldens as they may be copied into the source tree, and we don't
diff --git a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesMetadataProcessor.kt b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesMetadataProcessor.kt
new file mode 100644
index 0000000..100d869
--- /dev/null
+++ b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesMetadataProcessor.kt
@@ -0,0 +1,110 @@
+/*
+ * 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.systemfeatures
+
+import android.annotation.SdkConstant
+import com.squareup.javapoet.FieldSpec
+import com.squareup.javapoet.JavaFile
+import com.squareup.javapoet.TypeSpec
+import java.io.IOException
+import javax.annotation.processing.AbstractProcessor
+import javax.annotation.processing.ProcessingEnvironment
+import javax.annotation.processing.RoundEnvironment
+import javax.lang.model.SourceVersion
+import javax.lang.model.element.Modifier
+import javax.lang.model.element.TypeElement
+import javax.tools.Diagnostic
+
+/*
+ * Simple Java code generator for computing metadata for system features.
+ *
+ * <p>The output is a single class file, `com.android.internal.pm.SystemFeaturesMetadata`, with
+ * properties computed from feature constant definitions in the PackageManager class. This
+ * class is only produced if the processed environment includes PackageManager; all other
+ * invocations are ignored.
+ */
+class SystemFeaturesMetadataProcessor : AbstractProcessor() {
+
+    private lateinit var packageManagerType: TypeElement
+
+    override fun getSupportedSourceVersion(): SourceVersion = SourceVersion.latestSupported()
+
+    override fun getSupportedAnnotationTypes() = setOf(SDK_CONSTANT_ANNOTATION_NAME)
+
+    override fun init(processingEnv: ProcessingEnvironment) {
+        super.init(processingEnv)
+        packageManagerType =
+            processingEnv.elementUtils.getTypeElement("android.content.pm.PackageManager")!!
+    }
+
+    override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
+        if (roundEnv.processingOver()) {
+            return false
+        }
+
+        // We're only interested in feature constants defined in PackageManager.
+        var featureCount = 0
+        roundEnv.getElementsAnnotatedWith(SdkConstant::class.java).forEach {
+            if (
+                it.enclosingElement == packageManagerType &&
+                    it.getAnnotation(SdkConstant::class.java).value ==
+                        SdkConstant.SdkConstantType.FEATURE
+            ) {
+                featureCount++
+            }
+        }
+
+        if (featureCount == 0) {
+            // This is fine, and happens for any environment that doesn't include PackageManager.
+            return false
+        }
+
+        val systemFeatureMetadata =
+            TypeSpec.classBuilder("SystemFeaturesMetadata")
+                .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+                .addJavadoc("@hide")
+                .addField(
+                    FieldSpec.builder(Int::class.java, "SDK_FEATURE_COUNT")
+                        .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
+                        .addJavadoc(
+                            "The number of `@SdkConstant` features defined in PackageManager."
+                        )
+                        .addJavadoc("@hide")
+                        .initializer("\$L", featureCount)
+                        .build()
+                )
+                .build()
+
+        try {
+            JavaFile.builder("com.android.internal.pm", systemFeatureMetadata)
+                .skipJavaLangImports(true)
+                .build()
+                .writeTo(processingEnv.filer)
+        } catch (e: IOException) {
+            processingEnv.messager.printMessage(
+                Diagnostic.Kind.ERROR,
+                "Failed to write file: ${e.message}",
+            )
+        }
+
+        return true
+    }
+
+    companion object {
+        private val SDK_CONSTANT_ANNOTATION_NAME = SdkConstant::class.qualifiedName
+    }
+}
diff --git a/tools/systemfeatures/tests/src/PackageManager.java b/tools/systemfeatures/tests/src/PackageManager.java
index db67048..839a937 100644
--- a/tools/systemfeatures/tests/src/PackageManager.java
+++ b/tools/systemfeatures/tests/src/PackageManager.java
@@ -16,14 +16,33 @@
 
 package android.content.pm;
 
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+
 /** Stub for testing */
 public class PackageManager {
+    @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_AUTO = "automotive";
+
+    @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_PC = "pc";
+
+    @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_VULKAN = "vulkan";
+
+    @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_WATCH = "watch";
+
+    @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_WIFI = "wifi";
 
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String FEATURE_INTENT_CATEGORY = "intent_category_with_feature_name_prefix";
+
+    public static final String FEATURE_NOT_ANNOTATED = "not_annotated";
+
+    public static final String NOT_FEATURE = "not_feature";
+
     /** @hide */
     public boolean hasSystemFeature(String featureName, int version) {
         return false;
diff --git a/tools/systemfeatures/tests/src/SystemFeaturesMetadataProcessorTest.java b/tools/systemfeatures/tests/src/SystemFeaturesMetadataProcessorTest.java
new file mode 100644
index 0000000..4ffb5b9
--- /dev/null
+++ b/tools/systemfeatures/tests/src/SystemFeaturesMetadataProcessorTest.java
@@ -0,0 +1,36 @@
+/*
+ * 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.systemfeatures;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.android.internal.pm.SystemFeaturesMetadata;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class SystemFeaturesMetadataProcessorTest {
+
+    @Test
+    public void testSdkFeatureCount() {
+        // See the fake PackageManager definition in this directory.
+        // It defines 5 annotated features, and any/all other constants should be ignored.
+        assertThat(SystemFeaturesMetadata.SDK_FEATURE_COUNT).isEqualTo(5);
+    }
+}